VirtualBox

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

Last change on this file since 96763 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 23.1 KB
Line 
1/* $Id: initterm-r0drv-nt.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Initialization & Termination, R0 Driver, NT.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "the-nt-kernel.h"
42#include <iprt/asm-amd64-x86.h>
43#include <iprt/dbg.h>
44#include <iprt/errcore.h>
45#include <iprt/string.h>
46#include "internal/initterm.h"
47#include "internal-r0drv-nt.h"
48#include "symdb.h"
49#include "symdbdata.h"
50
51
52/*********************************************************************************************************************************
53* Global Variables *
54*********************************************************************************************************************************/
55/** ExAllocatePoolWithTag, introduced in W2K. */
56decltype(ExAllocatePoolWithTag) *g_pfnrtExAllocatePoolWithTag;
57/** ExFreePoolWithTag, introduced in W2K. */
58decltype(ExFreePoolWithTag) *g_pfnrtExFreePoolWithTag;
59/** ExSetTimerResolution, introduced in W2K. */
60PFNMYEXSETTIMERRESOLUTION g_pfnrtNtExSetTimerResolution;
61/** ExAllocateTimer, introduced in Windows 8.1 */
62PFNEXALLOCATETIMER g_pfnrtExAllocateTimer;
63/** ExDeleteTimer, introduced in Windows 8.1 */
64PFNEXDELETETIMER g_pfnrtExDeleteTimer;
65/** ExSetTimer, introduced in Windows 8.1 */
66PFNEXSETTIMER g_pfnrtExSetTimer;
67/** ExCancelTimer, introduced in Windows 8.1 */
68PFNEXCANCELTIMER g_pfnrtExCancelTimer;
69/** KeFlushQueuedDpcs, introduced in XP. */
70PFNMYKEFLUSHQUEUEDDPCS g_pfnrtNtKeFlushQueuedDpcs;
71/** HalRequestIpi, version introduced with windows 7. */
72PFNHALREQUESTIPI_W7PLUS g_pfnrtHalRequestIpiW7Plus;
73/** HalRequestIpi, version valid up to windows vista?? */
74PFNHALREQUESTIPI_PRE_W7 g_pfnrtHalRequestIpiPreW7;
75/** Worker for RTMpPokeCpu. */
76PFNRTSENDIPI g_pfnrtMpPokeCpuWorker;
77/** KeIpiGenericCall - Introduced in Windows Server 2003. */
78PFNRTKEIPIGENERICCALL g_pfnrtKeIpiGenericCall;
79/** KeSetTargetProcessorDpcEx - Introduced in Windows 7. */
80PFNKESETTARGETPROCESSORDPCEX g_pfnrtKeSetTargetProcessorDpcEx;
81/** KeInitializeAffinityEx - Introducted in Windows 7. */
82PFNKEINITIALIZEAFFINITYEX g_pfnrtKeInitializeAffinityEx;
83/** KeAddProcessorAffinityEx - Introducted in Windows 7. */
84PFNKEADDPROCESSORAFFINITYEX g_pfnrtKeAddProcessorAffinityEx;
85/** KeGetProcessorIndexFromNumber - Introducted in Windows 7. */
86PFNKEGETPROCESSORINDEXFROMNUMBER g_pfnrtKeGetProcessorIndexFromNumber;
87/** KeGetProcessorNumberFromIndex - Introducted in Windows 7. */
88PFNKEGETPROCESSORNUMBERFROMINDEX g_pfnrtKeGetProcessorNumberFromIndex;
89/** KeGetCurrentProcessorNumberEx - Introducted in Windows 7. */
90PFNKEGETCURRENTPROCESSORNUMBEREX g_pfnrtKeGetCurrentProcessorNumberEx;
91/** KeQueryActiveProcessors - Introducted in Windows 2000. */
92PFNKEQUERYACTIVEPROCESSORS g_pfnrtKeQueryActiveProcessors;
93/** KeQueryMaximumProcessorCount - Introducted in Vista and obsoleted W7. */
94PFNKEQUERYMAXIMUMPROCESSORCOUNT g_pfnrtKeQueryMaximumProcessorCount;
95/** KeQueryMaximumProcessorCountEx - Introducted in Windows 7. */
96PFNKEQUERYMAXIMUMPROCESSORCOUNTEX g_pfnrtKeQueryMaximumProcessorCountEx;
97/** KeQueryMaximumGroupCount - Introducted in Windows 7. */
98PFNKEQUERYMAXIMUMGROUPCOUNT g_pfnrtKeQueryMaximumGroupCount;
99/** KeQueryActiveProcessorCount - Introducted in Vista and obsoleted W7. */
100PFNKEQUERYACTIVEPROCESSORCOUNT g_pfnrtKeQueryActiveProcessorCount;
101/** KeQueryActiveProcessorCountEx - Introducted in Windows 7. */
102PFNKEQUERYACTIVEPROCESSORCOUNTEX g_pfnrtKeQueryActiveProcessorCountEx;
103/** KeQueryLogicalProcessorRelationship - Introducted in Windows 7. */
104PFNKEQUERYLOGICALPROCESSORRELATIONSHIP g_pfnrtKeQueryLogicalProcessorRelationship;
105/** KeRegisterProcessorChangeCallback - Introducted in Windows 7. */
106PFNKEREGISTERPROCESSORCHANGECALLBACK g_pfnrtKeRegisterProcessorChangeCallback;
107/** KeDeregisterProcessorChangeCallback - Introducted in Windows 7. */
108PFNKEDEREGISTERPROCESSORCHANGECALLBACK g_pfnrtKeDeregisterProcessorChangeCallback;
109/** KeSetImportanceDpc - Introducted in NT 3.51. */
110decltype(KeSetImportanceDpc) *g_pfnrtKeSetImportanceDpc;
111/** KeSetTargetProcessorDpc - Introducted in NT 3.51. */
112decltype(KeSetTargetProcessorDpc) *g_pfnrtKeSetTargetProcessorDpc;
113/** KeInitializeTimerEx - Introduced in NT 4. */
114decltype(KeInitializeTimerEx) *g_pfnrtKeInitializeTimerEx;
115/** KeShouldYieldProcessor - Introduced in Windows 10. */
116PFNKESHOULDYIELDPROCESSOR g_pfnrtKeShouldYieldProcessor;
117/** Pointer to the MmProtectMdlSystemAddress kernel function if it's available.
118 * This API was introduced in XP. */
119decltype(MmProtectMdlSystemAddress) *g_pfnrtMmProtectMdlSystemAddress;
120/** MmAllocatePagesForMdl - Introduced in Windows 2000. */
121decltype(MmAllocatePagesForMdl) *g_pfnrtMmAllocatePagesForMdl;
122/** MmAllocatePagesForMdlEx - Introduced in Windows Server 2003 SP1. */
123PFNMMALLOCATEPAGESFORMDLEX g_pfnrtMmAllocatePagesForMdlEx;
124/** MmFreePagesFromMdl - Introduced in Windows 2000. */
125decltype(MmFreePagesFromMdl) *g_pfnrtMmFreePagesFromMdl;
126/** MmMapLockedPagesSpecifyCache - Introduced in Windows NT4 SP4. */
127decltype(MmMapLockedPagesSpecifyCache) *g_pfnrtMmMapLockedPagesSpecifyCache;
128/** MmAllocateContiguousMemorySpecifyCache - Introduced in Windows 2000. */
129decltype(MmAllocateContiguousMemorySpecifyCache) *g_pfnrtMmAllocateContiguousMemorySpecifyCache;
130/** MmSecureVirtualMemory - Introduced in NT 3.51. */
131decltype(MmSecureVirtualMemory) *g_pfnrtMmSecureVirtualMemory;
132/** MmUnsecureVirtualMemory - Introduced in NT 3.51. */
133decltype(MmUnsecureVirtualMemory) *g_pfnrtMmUnsecureVirtualMemory;
134/** PsIsThreadTerminating - Introduced in NT 3.50. */
135decltype(PsIsThreadTerminating) *g_pfnrtPsIsThreadTerminating;
136/** RtlGetVersion, introduced in ??. */
137PFNRTRTLGETVERSION g_pfnrtRtlGetVersion;
138#ifdef RT_ARCH_X86
139/** KeQueryInterruptTime - exported/new in Windows 2000. */
140PFNRTKEQUERYINTERRUPTTIME g_pfnrtKeQueryInterruptTime;
141#endif
142/** KeQueryInterruptTimePrecise - new in Windows 8. */
143PFNRTKEQUERYINTERRUPTTIMEPRECISE g_pfnrtKeQueryInterruptTimePrecise;
144/** KeQuerySystemTimePrecise - new in Windows 8. */
145PFNRTKEQUERYSYSTEMTIMEPRECISE g_pfnrtKeQuerySystemTimePrecise;
146
147/** Offset of the _KPRCB::QuantumEnd field. 0 if not found. */
148uint32_t g_offrtNtPbQuantumEnd;
149/** Size of the _KPRCB::QuantumEnd field. 0 if not found. */
150uint32_t g_cbrtNtPbQuantumEnd;
151/** Offset of the _KPRCB::DpcQueueDepth field. 0 if not found. */
152uint32_t g_offrtNtPbDpcQueueDepth;
153
154/** The combined NT version, see RTNT_MAKE_VERSION. */
155uint32_t g_uRtNtVersion = RTNT_MAKE_VERSION(4, 0);
156/** The major version number. */
157uint8_t g_uRtNtMajorVer;
158/** The minor version number. */
159uint8_t g_uRtNtMinorVer;
160/** The build number. */
161uint32_t g_uRtNtBuildNo;
162
163/** Pointer to the MmHighestUserAddress kernel variable - can be NULL. */
164uintptr_t const *g_puRtMmHighestUserAddress;
165/** Pointer to the MmSystemRangeStart kernel variable - can be NULL. */
166uintptr_t const *g_puRtMmSystemRangeStart;
167
168
169/**
170 * Determines the NT kernel verison information.
171 *
172 * @param pOsVerInfo Where to return the version information.
173 *
174 * @remarks pOsVerInfo->fSmp is only definitive if @c true.
175 * @remarks pOsVerInfo->uCsdNo is set to MY_NIL_CSD if it cannot be determined.
176 */
177static void rtR0NtGetOsVersionInfo(PRTNTSDBOSVER pOsVerInfo)
178{
179 ULONG ulMajorVersion = 0;
180 ULONG ulMinorVersion = 0;
181 ULONG ulBuildNumber = 0;
182
183 pOsVerInfo->fChecked = PsGetVersion(&ulMajorVersion, &ulMinorVersion, &ulBuildNumber, NULL) == TRUE;
184 pOsVerInfo->uMajorVer = (uint8_t)ulMajorVersion;
185 pOsVerInfo->uMinorVer = (uint8_t)ulMinorVersion;
186 pOsVerInfo->uBuildNo = ulBuildNumber;
187#define MY_NIL_CSD 0x3f
188 pOsVerInfo->uCsdNo = MY_NIL_CSD;
189
190 if (g_pfnrtRtlGetVersion)
191 {
192 RTL_OSVERSIONINFOEXW VerInfo;
193 RT_ZERO(VerInfo);
194 VerInfo.dwOSVersionInfoSize = sizeof(VerInfo);
195
196 NTSTATUS rcNt = g_pfnrtRtlGetVersion(&VerInfo);
197 if (NT_SUCCESS(rcNt))
198 pOsVerInfo->uCsdNo = VerInfo.wServicePackMajor;
199 }
200
201 /* Note! We cannot quite say if something is MP or UNI. So, fSmp is
202 redefined to indicate that it must be MP.
203 Note! RTMpGetCount is not available here. */
204 pOsVerInfo->fSmp = ulMajorVersion >= 6; /* Vista and later has no UNI kernel AFAIK. */
205 if (!pOsVerInfo->fSmp)
206 {
207 if ( g_pfnrtKeQueryMaximumProcessorCountEx
208 && g_pfnrtKeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS) > 1)
209 pOsVerInfo->fSmp = true;
210 else if ( g_pfnrtKeQueryMaximumProcessorCount
211 && g_pfnrtKeQueryMaximumProcessorCount() > 1)
212 pOsVerInfo->fSmp = true;
213 else if ( g_pfnrtKeQueryActiveProcessors
214 && g_pfnrtKeQueryActiveProcessors() > 1)
215 pOsVerInfo->fSmp = true;
216 else if (KeNumberProcessors > 1)
217 pOsVerInfo->fSmp = true;
218 }
219}
220
221
222/**
223 * Tries a set against the current kernel.
224 *
225 * @retval true if it matched up, global variables are updated.
226 * @retval false otherwise (no globals updated).
227 * @param pSet The data set.
228 * @param pbPrcb Pointer to the processor control block.
229 * @param pszVendor Pointer to the processor vendor string.
230 * @param pOsVerInfo The OS version info.
231 */
232static bool rtR0NtTryMatchSymSet(PCRTNTSDBSET pSet, uint8_t *pbPrcb, const char *pszVendor, PCRTNTSDBOSVER pOsVerInfo)
233{
234 /*
235 * Don't bother trying stuff where the NT kernel version number differs, or
236 * if the build type or SMPness doesn't match up.
237 */
238 if ( pSet->OsVerInfo.uMajorVer != pOsVerInfo->uMajorVer
239 || pSet->OsVerInfo.uMinorVer != pOsVerInfo->uMinorVer
240 || pSet->OsVerInfo.fChecked != pOsVerInfo->fChecked
241 || (!pSet->OsVerInfo.fSmp && pOsVerInfo->fSmp /*must-be-smp*/) )
242 {
243 //DbgPrint("IPRT: #%d Version/type mismatch.\n", pSet - &g_artNtSdbSets[0]);
244 return false;
245 }
246
247 /*
248 * Do the CPU vendor test.
249 *
250 * Note! The MmIsAddressValid call is the real #PF security here as the
251 * __try/__except has limited/no ability to catch everything we need.
252 */
253 char *pszPrcbVendorString = (char *)&pbPrcb[pSet->KPRCB.offVendorString];
254 if (!MmIsAddressValid(&pszPrcbVendorString[4 * 3 - 1]))
255 {
256 //DbgPrint("IPRT: #%d invalid vendor string address.\n", pSet - &g_artNtSdbSets[0]);
257 return false;
258 }
259 __try
260 {
261 if (memcmp(pszPrcbVendorString, pszVendor, RT_MIN(4 * 3, pSet->KPRCB.cbVendorString)) != 0)
262 {
263 //DbgPrint("IPRT: #%d Vendor string mismatch.\n", pSet - &g_artNtSdbSets[0]);
264 return false;
265 }
266 }
267 __except(EXCEPTION_EXECUTE_HANDLER)
268 {
269 DbgPrint("IPRT: %#d Exception\n", pSet - &g_artNtSdbSets[0]);
270 return false;
271 }
272
273 /*
274 * Got a match, update the global variables and report success.
275 */
276 g_offrtNtPbQuantumEnd = pSet->KPRCB.offQuantumEnd;
277 g_cbrtNtPbQuantumEnd = pSet->KPRCB.cbQuantumEnd;
278 g_offrtNtPbDpcQueueDepth = pSet->KPRCB.offDpcQueueDepth;
279
280#if 0
281 DbgPrint("IPRT: Using data set #%u for %u.%usp%u build %u %s %s.\n",
282 pSet - &g_artNtSdbSets[0],
283 pSet->OsVerInfo.uMajorVer,
284 pSet->OsVerInfo.uMinorVer,
285 pSet->OsVerInfo.uCsdNo,
286 pSet->OsVerInfo.uBuildNo,
287 pSet->OsVerInfo.fSmp ? "smp" : "uni",
288 pSet->OsVerInfo.fChecked ? "checked" : "free");
289#endif
290 return true;
291}
292
293
294DECLHIDDEN(int) rtR0InitNative(void)
295{
296 /*
297 * Preinitialize g_uRtNtVersion so RTMemAlloc uses the right kind of pool
298 * when RTR0DbgKrnlInfoOpen calls it.
299 */
300 RTNTSDBOSVER OsVerInfo;
301 rtR0NtGetOsVersionInfo(&OsVerInfo);
302 g_uRtNtVersion = RTNT_MAKE_VERSION(OsVerInfo.uMajorVer, OsVerInfo.uMinorVer);
303 g_uRtNtMinorVer = OsVerInfo.uMinorVer;
304 g_uRtNtMajorVer = OsVerInfo.uMajorVer;
305 g_uRtNtBuildNo = OsVerInfo.uBuildNo;
306
307 /*
308 * Initialize the function pointers.
309 */
310 RTDBGKRNLINFO hKrnlInfo;
311 int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0/*fFlags*/);
312 AssertRCReturn(rc, rc);
313
314#define GET_SYSTEM_ROUTINE_EX(a_Prf, a_Name, a_pfnType) \
315 do { RT_CONCAT3(g_pfnrt, a_Prf, a_Name) = (a_pfnType)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, #a_Name); } while (0)
316#define GET_SYSTEM_ROUTINE(a_Name) GET_SYSTEM_ROUTINE_EX(RT_NOTHING, a_Name, decltype(a_Name) *)
317#define GET_SYSTEM_ROUTINE_PRF(a_Prf,a_Name) GET_SYSTEM_ROUTINE_EX(a_Prf, a_Name, decltype(a_Name) *)
318#define GET_SYSTEM_ROUTINE_TYPE(a_Name, a_pfnType) GET_SYSTEM_ROUTINE_EX(RT_NOTHING, a_Name, a_pfnType)
319
320 GET_SYSTEM_ROUTINE(ExAllocatePoolWithTag);
321 GET_SYSTEM_ROUTINE(ExFreePoolWithTag);
322 GET_SYSTEM_ROUTINE_PRF(Nt,ExSetTimerResolution);
323 GET_SYSTEM_ROUTINE_TYPE(ExAllocateTimer, PFNEXALLOCATETIMER);
324 GET_SYSTEM_ROUTINE_TYPE(ExDeleteTimer, PFNEXDELETETIMER);
325 GET_SYSTEM_ROUTINE_TYPE(ExSetTimer, PFNEXSETTIMER);
326 GET_SYSTEM_ROUTINE_TYPE(ExCancelTimer, PFNEXCANCELTIMER);
327 GET_SYSTEM_ROUTINE_PRF(Nt,KeFlushQueuedDpcs);
328 GET_SYSTEM_ROUTINE(KeIpiGenericCall);
329 GET_SYSTEM_ROUTINE(KeSetTargetProcessorDpcEx);
330 GET_SYSTEM_ROUTINE(KeInitializeAffinityEx);
331 GET_SYSTEM_ROUTINE(KeAddProcessorAffinityEx);
332 GET_SYSTEM_ROUTINE_TYPE(KeGetProcessorIndexFromNumber, PFNKEGETPROCESSORINDEXFROMNUMBER);
333 GET_SYSTEM_ROUTINE(KeGetProcessorNumberFromIndex);
334 GET_SYSTEM_ROUTINE_TYPE(KeGetCurrentProcessorNumberEx, PFNKEGETCURRENTPROCESSORNUMBEREX);
335 GET_SYSTEM_ROUTINE(KeQueryActiveProcessors);
336 GET_SYSTEM_ROUTINE(KeQueryMaximumProcessorCount);
337 GET_SYSTEM_ROUTINE(KeQueryMaximumProcessorCountEx);
338 GET_SYSTEM_ROUTINE(KeQueryMaximumGroupCount);
339 GET_SYSTEM_ROUTINE(KeQueryActiveProcessorCount);
340 GET_SYSTEM_ROUTINE(KeQueryActiveProcessorCountEx);
341 GET_SYSTEM_ROUTINE(KeQueryLogicalProcessorRelationship);
342 GET_SYSTEM_ROUTINE(KeRegisterProcessorChangeCallback);
343 GET_SYSTEM_ROUTINE(KeDeregisterProcessorChangeCallback);
344 GET_SYSTEM_ROUTINE(KeSetImportanceDpc);
345 GET_SYSTEM_ROUTINE(KeSetTargetProcessorDpc);
346 GET_SYSTEM_ROUTINE(KeInitializeTimerEx);
347 GET_SYSTEM_ROUTINE_TYPE(KeShouldYieldProcessor, PFNKESHOULDYIELDPROCESSOR);
348 GET_SYSTEM_ROUTINE(MmProtectMdlSystemAddress);
349 GET_SYSTEM_ROUTINE(MmAllocatePagesForMdl);
350 GET_SYSTEM_ROUTINE(MmAllocatePagesForMdlEx);
351 GET_SYSTEM_ROUTINE(MmFreePagesFromMdl);
352 GET_SYSTEM_ROUTINE(MmMapLockedPagesSpecifyCache);
353 GET_SYSTEM_ROUTINE(MmAllocateContiguousMemorySpecifyCache);
354 GET_SYSTEM_ROUTINE(MmSecureVirtualMemory);
355 GET_SYSTEM_ROUTINE(MmUnsecureVirtualMemory);
356
357 GET_SYSTEM_ROUTINE_TYPE(RtlGetVersion, PFNRTRTLGETVERSION);
358#ifdef RT_ARCH_X86
359 GET_SYSTEM_ROUTINE(KeQueryInterruptTime);
360#endif
361 GET_SYSTEM_ROUTINE_TYPE(KeQueryInterruptTimePrecise, PFNRTKEQUERYINTERRUPTTIMEPRECISE);
362 GET_SYSTEM_ROUTINE_TYPE(KeQuerySystemTimePrecise, PFNRTKEQUERYSYSTEMTIMEPRECISE);
363
364 g_pfnrtHalRequestIpiW7Plus = (PFNHALREQUESTIPI_W7PLUS)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "HalRequestIpi");
365 g_pfnrtHalRequestIpiPreW7 = (PFNHALREQUESTIPI_PRE_W7)g_pfnrtHalRequestIpiW7Plus;
366
367 g_puRtMmHighestUserAddress = (uintptr_t const *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "MmHighestUserAddress");
368 g_puRtMmSystemRangeStart = (uintptr_t const *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "MmSystemRangeStart");
369
370#ifdef RT_ARCH_X86
371 rc = rtR0Nt3InitSymbols(hKrnlInfo);
372 RTR0DbgKrnlInfoRelease(hKrnlInfo);
373 if (RT_FAILURE(rc))
374 return rc;
375#else
376 RTR0DbgKrnlInfoRelease(hKrnlInfo);
377#endif
378
379 /*
380 * Get and publish the definitive NT version.
381 */
382 rtR0NtGetOsVersionInfo(&OsVerInfo);
383 g_uRtNtVersion = RTNT_MAKE_VERSION(OsVerInfo.uMajorVer, OsVerInfo.uMinorVer);
384 g_uRtNtMinorVer = OsVerInfo.uMinorVer;
385 g_uRtNtMajorVer = OsVerInfo.uMajorVer;
386 g_uRtNtBuildNo = OsVerInfo.uBuildNo;
387
388
389 /*
390 * HACK ALERT! (and déjà vu warning - remember win32k.sys on OS/2?)
391 *
392 * Try find _KPRCB::QuantumEnd and _KPRCB::[DpcData.]DpcQueueDepth.
393 * For purpose of verification we use the VendorString member (12+1 chars).
394 *
395 * The offsets was initially derived by poking around with windbg
396 * (dt _KPRCB, !prcb ++, and such like). Systematic harvesting was then
397 * planned using dia2dump, grep and the symbol pack in a manner like this:
398 * dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString"
399 *
400 * The final solution ended up using a custom harvester program called
401 * ntBldSymDb that recursively searches thru unpacked symbol packages for
402 * the desired structure offsets. The program assumes that the packages
403 * are unpacked into directories with the same name as the package, with
404 * exception of some of the w2k packages which requires a 'w2k' prefix to
405 * be distinguishable from another.
406 */
407
408 /*
409 * Gather consistent CPU vendor string and PRCB pointers.
410 */
411 KIRQL OldIrql;
412 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */
413
414 union
415 {
416 uint32_t auRegs[4];
417 char szVendor[4*3+1];
418 } u;
419 ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]);
420 u.szVendor[4*3] = '\0';
421
422 uint8_t *pbPrcb;
423 __try /* Warning. This try/except statement may provide some false safety. */
424 {
425#if defined(RT_ARCH_X86)
426 PKPCR pPcr = (PKPCR)__readfsdword(RT_UOFFSETOF(KPCR,SelfPcr));
427 pbPrcb = (uint8_t *)pPcr->Prcb;
428#elif defined(RT_ARCH_AMD64)
429 PKPCR pPcr = (PKPCR)__readgsqword(RT_UOFFSETOF(KPCR,Self));
430 pbPrcb = (uint8_t *)pPcr->CurrentPrcb;
431#else
432# error "port me"
433 pbPrcb = NULL;
434#endif
435 }
436 __except(EXCEPTION_EXECUTE_HANDLER)
437 {
438 pbPrcb = NULL;
439 }
440
441 /*
442 * Search the database
443 */
444 if (pbPrcb)
445 {
446 /* Find the best matching kernel version based on build number. */
447 uint32_t iBest = UINT32_MAX;
448 int32_t iBestDelta = INT32_MAX;
449 for (uint32_t i = 0; i < RT_ELEMENTS(g_artNtSdbSets); i++)
450 {
451 if (g_artNtSdbSets[i].OsVerInfo.fChecked != OsVerInfo.fChecked)
452 continue;
453 if (OsVerInfo.fSmp /*must-be-smp*/ && !g_artNtSdbSets[i].OsVerInfo.fSmp)
454 continue;
455
456 int32_t iDelta = RT_ABS((int32_t)OsVerInfo.uBuildNo - (int32_t)g_artNtSdbSets[i].OsVerInfo.uBuildNo);
457 if ( iDelta == 0
458 && (g_artNtSdbSets[i].OsVerInfo.uCsdNo == OsVerInfo.uCsdNo || OsVerInfo.uCsdNo == MY_NIL_CSD))
459 {
460 /* prefect */
461 iBestDelta = iDelta;
462 iBest = i;
463 break;
464 }
465 if ( iDelta < iBestDelta
466 || iBest == UINT32_MAX
467 || ( iDelta == iBestDelta
468 && OsVerInfo.uCsdNo != MY_NIL_CSD
469 && RT_ABS(g_artNtSdbSets[i ].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo)
470 < RT_ABS(g_artNtSdbSets[iBest].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo)
471 )
472 )
473 {
474 iBestDelta = iDelta;
475 iBest = i;
476 }
477 }
478 if (iBest < RT_ELEMENTS(g_artNtSdbSets))
479 {
480 /* Try all sets: iBest -> End; iBest -> Start. */
481 bool fDone = false;
482 int32_t i = iBest;
483 while ( i < RT_ELEMENTS(g_artNtSdbSets)
484 && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo)))
485 i++;
486 if (!fDone)
487 {
488 i = (int32_t)iBest - 1;
489 while ( i >= 0
490 && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo)))
491 i--;
492 }
493 }
494 else
495 DbgPrint("IPRT: Failed to locate data set.\n");
496 }
497 else
498 DbgPrint("IPRT: Failed to get PCBR pointer.\n");
499
500 KeLowerIrql(OldIrql); /* Lowering the IRQL early in the hope that we may catch exceptions below. */
501
502#ifndef IN_GUEST
503 if (!g_offrtNtPbQuantumEnd && !g_offrtNtPbDpcQueueDepth)
504 DbgPrint("IPRT: Neither _KPRCB::QuantumEnd nor _KPRCB::DpcQueueDepth was not found! Kernel %u.%u %u %s\n",
505 OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free");
506# ifdef DEBUG
507 else
508 DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %u.%u %u %s\n",
509 g_offrtNtPbQuantumEnd, g_cbrtNtPbQuantumEnd, g_offrtNtPbDpcQueueDepth, g_offrtNtPbDpcQueueDepth,
510 OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free");
511# endif
512#endif
513
514 /*
515 * Initialize multi processor stuff. This registers a callback, so
516 * we call rtR0TermNative to do the deregistration on failure.
517 */
518 rc = rtR0MpNtInit(&OsVerInfo);
519 if (RT_FAILURE(rc))
520 {
521 rtR0TermNative();
522 DbgPrint("IPRT: Fatal: rtR0MpNtInit failed: %d\n", rc);
523 return rc;
524 }
525
526 return VINF_SUCCESS;
527}
528
529
530DECLHIDDEN(void) rtR0TermNative(void)
531{
532 rtR0MpNtTerm();
533}
534
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