VirtualBox

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

Last change on this file since 91852 was 91449, checked in by vboxsync, 3 years ago

IPRT/memobj: MmAllocatePagesForMdlEx is not visible when building the NT3+ VBoxGuest, so typedef a pointer to it instead lf of using decltype. bugref:5324

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