VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp@ 23506

Last change on this file since 23506 was 23506, checked in by vboxsync, 15 years ago

Use HalSendSoftwareInterrupt in Windows 7 (not exported in Vista)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.4 KB
Line 
1/* $Id: initterm-r0drv-nt.cpp 23506 2009-10-02 11:12:21Z vboxsync $ */
2/** @file
3 * IPRT - Initialization & Termination, R0 Driver, NT.
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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include "the-nt-kernel.h"
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/mp.h>
38#include <iprt/string.h>
39#include "internal/initterm.h"
40#include "internal-r0drv-nt.h"
41
42
43/*******************************************************************************
44* Global Variables *
45*******************************************************************************/
46/** The Nt CPU set.
47 * KeQueryActiveProcssors() cannot be called at all IRQLs and therefore we'll
48 * have to cache it. Fortunately, Nt doesn't really support taking CPUs offline
49 * or online. It's first with W2K8 that support for CPU hotplugging was added.
50 * Once we start caring about this, we'll simply let the native MP event callback
51 * and update this variable as CPUs comes online. (The code is done already.)
52 */
53RTCPUSET g_rtMpNtCpuSet;
54
55/** ExSetTimerResolution, introduced in W2K. */
56PFNMYEXSETTIMERRESOLUTION g_pfnrtNtExSetTimerResolution;
57/** KeFlushQueuedDpcs, introduced in XP. */
58PFNMYKEFLUSHQUEUEDDPCS g_pfnrtNtKeFlushQueuedDpcs;
59/** HalRequestIpi, introduced in ??. */
60PFNHALREQUESTIPI g_pfnrtNtHalRequestIpi;
61/** HalSendSoftwareInterrupt */
62PFNHALSENDSOFTWAREINTERRUPT g_pfnrtNtHalSendSoftwareInterrupt;
63/** SendIpi handler based on Windows version */
64PFNRTSENDIPI g_pfnrtSendIpi;
65
66/** Offset of the _KPRCB::QuantumEnd field. 0 if not found. */
67uint32_t g_offrtNtPbQuantumEnd;
68/** Size of the _KPRCB::QuantumEnd field. 0 if not found. */
69uint32_t g_cbrtNtPbQuantumEnd;
70/** Offset of the _KPRCB::DpcQueueDepth field. 0 if not found. */
71uint32_t g_offrtNtPbDpcQueueDepth;
72
73
74
75int rtR0InitNative(void)
76{
77 /*
78 * Init the Nt cpu set.
79 */
80#ifdef IPRT_TARGET_NT4
81 KAFFINITY ActiveProcessors = (UINT64_C(1) << KeNumberProcessors) - UINT64_C(1);
82#else
83 KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
84#endif
85 RTCpuSetEmpty(&g_rtMpNtCpuSet);
86 RTCpuSetFromU64(&g_rtMpNtCpuSet, ActiveProcessors);
87
88#ifdef IPRT_TARGET_NT4
89 g_pfnrtNtExSetTimerResolution = NULL;
90 g_pfnrtNtKeFlushQueuedDpcs = NULL;
91 g_pfnrtNtHalRequestIpi = NULL;
92 g_pfnrtNtHalSendSoftwareInterrupt = NULL;
93#else
94 /*
95 * Initialize the function pointers.
96 */
97 UNICODE_STRING RoutineName;
98 RtlInitUnicodeString(&RoutineName, L"ExSetTimerResolution");
99 g_pfnrtNtExSetTimerResolution = (PFNMYEXSETTIMERRESOLUTION)MmGetSystemRoutineAddress(&RoutineName);
100
101 RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs");
102 g_pfnrtNtKeFlushQueuedDpcs = (PFNMYKEFLUSHQUEUEDDPCS)MmGetSystemRoutineAddress(&RoutineName);
103
104 RtlInitUnicodeString(&RoutineName, L"HalRequestIpi");
105 g_pfnrtNtHalRequestIpi = (PFNHALREQUESTIPI)MmGetSystemRoutineAddress(&RoutineName);
106
107 RtlInitUnicodeString(&RoutineName, L"HalSendSoftwareInterrupt");
108 g_pfnrtNtHalSendSoftwareInterrupt = (PFNHALSENDSOFTWAREINTERRUPT)MmGetSystemRoutineAddress(&RoutineName);
109#endif
110
111 /*
112 * Get some info that might come in handy below.
113 */
114 ULONG MajorVersion = 0;
115 ULONG MinorVersion = 0;
116 ULONG BuildNumber = 0;
117 BOOLEAN fChecked = PsGetVersion(&MajorVersion, &MinorVersion, &BuildNumber, NULL);
118
119 g_pfnrtSendIpi = rtMpSendIpiDummy;
120#ifndef IPRT_TARGET_NT4
121 if ( g_pfnrtNtHalRequestIpi
122 && MajorVersion == 6
123 && MinorVersion == 0)
124 {
125 /* Vista or Windows Server 2008 */
126 g_pfnrtSendIpi = rtMpSendIpiVista;
127 }
128 else
129 if ( g_pfnrtNtHalSendSoftwareInterrupt
130 && MajorVersion == 6
131 && MinorVersion == 1)
132 {
133 /* Windows 7 or Windows Server 2008 R2 */
134 g_pfnrtSendIpi = rtMpSendIpiWin7;
135 }
136 /* Windows XP should send always send an IPI -> VERIFY */
137#endif
138 KIRQL OldIrql;
139 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */
140
141 union
142 {
143 uint32_t auRegs[4];
144 char szVendor[4*3+1];
145 } u;
146 ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]);
147 u.szVendor[4*3] = '\0';
148
149 /*
150 * HACK ALERT (and déjà vu warning)!
151 *
152 * Try find _KPRCB::QuantumEnd and _KPRCB::[DpcData.]DpcQueueDepth.
153 * For purpose of verification we use the VendorString member (12+1 chars).
154 *
155 * The offsets was initially derived by poking around with windbg
156 * (dt _KPRCB, !prcb ++, and such like). Systematic harvesting is now done
157 * by means of dia2dump, grep and the symbol packs. Typically:
158 * dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString"
159 */
160 /** @todo array w/ data + script for extracting a row. (save space + readability; table will be short.) */
161 __try
162 {
163#if defined(RT_ARCH_X86)
164 PKPCR pPcr = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr));
165 uint8_t *pbPrcb = (uint8_t *)pPcr->Prcb;
166
167 if ( BuildNumber == 2600 /* XP SP2 */
168 && !memcmp(&pbPrcb[0x900], &u.szVendor[0], 4*3))
169 {
170 g_offrtNtPbQuantumEnd = 0x88c;
171 g_cbrtNtPbQuantumEnd = 4;
172 g_offrtNtPbDpcQueueDepth = 0x870;
173 }
174 /* WindowsVista.6002.090410-1830.x86fre.Symbols.exe
175 WindowsVista.6002.090410-1830.x86chk.Symbols.exe
176 WindowsVista.6002.090130-1715.x86fre.Symbols.exe
177 WindowsVista.6002.090130-1715.x86chk.Symbols.exe */
178 else if ( BuildNumber == 6002
179 && !memcmp(&pbPrcb[0x1c2c], &u.szVendor[0], 4*3))
180 {
181 g_offrtNtPbQuantumEnd = 0x1a41;
182 g_cbrtNtPbQuantumEnd = 1;
183 g_offrtNtPbDpcQueueDepth = 0x19e0 + 0xc;
184 }
185
186 /** @todo more */
187 //pbQuantumEnd = (uint8_t volatile *)pPcr->Prcb + 0x1a41;
188
189#elif defined(RT_ARCH_AMD64)
190 PKPCR pPcr = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self));
191 uint8_t *pbPrcb = (uint8_t *)pPcr->CurrentPrcb;
192
193 if ( BuildNumber == 3790 /* XP64 / W2K3-AMD64 SP1 */
194 && !memcmp(&pbPrcb[0x22b4], &u.szVendor[0], 4*3))
195 {
196 g_offrtNtPbQuantumEnd = 0x1f75;
197 g_cbrtNtPbQuantumEnd = 1;
198 g_offrtNtPbDpcQueueDepth = 0x1f00 + 0x18;
199 }
200 else if ( BuildNumber == 6000 /* Vista/AMD64 */
201 && !memcmp(&pbPrcb[0x38bc], &u.szVendor[0], 4*3))
202 {
203 g_offrtNtPbQuantumEnd = 0x3375;
204 g_cbrtNtPbQuantumEnd = 1;
205 g_offrtNtPbDpcQueueDepth = 0x3300 + 0x18;
206 }
207 /* WindowsVista.6002.090410-1830.amd64fre.Symbols
208 WindowsVista.6002.090130-1715.amd64fre.Symbols
209 WindowsVista.6002.090410-1830.amd64chk.Symbols */
210 else if ( BuildNumber == 6002
211 && !memcmp(&pbPrcb[0x399c], &u.szVendor[0], 4*3))
212 {
213 g_offrtNtPbQuantumEnd = 0x3475;
214 g_cbrtNtPbQuantumEnd = 1;
215 g_offrtNtPbDpcQueueDepth = 0x3400 + 0x18;
216 }
217
218#else
219# error "port me"
220#endif
221 }
222 __except(EXCEPTION_EXECUTE_HANDLER) /** @todo this handler doesn't seem to work... Because of Irql? */
223 {
224 g_offrtNtPbQuantumEnd = 0;
225 g_cbrtNtPbQuantumEnd = 0;
226 g_offrtNtPbDpcQueueDepth = 0;
227 }
228
229 KeLowerIrql(OldIrql);
230
231#ifndef IN_GUEST /** @todo fix above for all Nt versions. */
232 if (!g_offrtNtPbQuantumEnd && !g_offrtNtPbDpcQueueDepth)
233 DbgPrint("IPRT: Neither _KPRCB::QuantumEnd nor _KPRCB::DpcQueueDepth was not found! Kernel %u.%u %u %s\n",
234 MajorVersion, MinorVersion, BuildNumber, fChecked ? "checked" : "free");
235# ifdef DEBUG
236 else
237 DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %ul.%ul %ul %s\n",
238 g_offrtNtPbQuantumEnd, g_cbrtNtPbQuantumEnd, g_offrtNtPbDpcQueueDepth,
239 MajorVersion, MinorVersion, BuildNumber, fChecked ? "checked" : "free");
240# endif
241#endif
242
243 return VINF_SUCCESS;
244}
245
246
247void rtR0TermNative(void)
248{
249}
250
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