VirtualBox

Changeset 64234 in vbox


Ignore:
Timestamp:
Oct 13, 2016 10:10:42 AM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
111243
Message:

IPRT: Implemented processor group support for the ring-0 code.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/err.h

    r62473 r64234  
    951951 * creating a process as a given user. IQ is also called 'Increase quotas'. */
    952952#define VERR_PROC_IQ_PRIV_NOT_HELD          (-22413)
     953/** The system has too many CPUs. */
     954#define VERR_MP_TOO_MANY_CPUS               (-22414)
    953955/** @} */
    954956
  • trunk/include/iprt/nt/nt.h

    r64219 r64234  
    24312431typedef  NTSTATUS (NTAPI *PFNKEGETPROCESSORNUMBERFROMINDEX)(KEPROCESSORINDEX idxProcessor, PPROCESSOR_NUMBER pProcNumber);
    24322432typedef  KEPROCESSORINDEX (NTAPI *PFNKEGETPROCESSORINDEXFROMNUMBER)(const PROCESSOR_NUMBER *pProcNumber);
     2433typedef  NTSTATUS (NTAPI *PFNKEGETPROCESSORNUMBERFROMINDEX)(KEPROCESSORINDEX ProcIndex, PROCESSOR_NUMBER *pProcNumber);
     2434typedef  KEPROCESSORINDEX (NTAPI *PFNKEGETCURRENTPROCESSORNUMBEREX)(const PROCESSOR_NUMBER *pProcNumber);
     2435typedef  KAFFINITY (NTAPI *PFNKEQUERYACTIVEPROCESSORS)(VOID);
     2436typedef  ULONG   (NTAPI *PFNKEQUERYMAXIMUMPROCESSORCOUNT)(VOID);
     2437typedef  ULONG   (NTAPI *PFNKEQUERYMAXIMUMPROCESSORCOUNTEX)(USHORT GroupNumber);
     2438typedef  USHORT  (NTAPI *PFNKEQUERYMAXIMUMGROUPCOUNT)(VOID);
     2439typedef  NTSTATUS (NTAPI *PFNKEQUERYLOGICALPROCESSORRELATIONSHIP)(PROCESSOR_NUMBER *pProcNumber,
     2440                                                                  LOGICAL_PROCESSOR_RELATIONSHIP RelationShipType,
     2441                                                                  SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pInfo, PULONG pcbInfo);
     2442typedef  PVOID   (NTAPI *PFNKEREGISTERPROCESSORCHANGECALLBACK)(PPROCESSOR_CALLBACK_FUNCTION pfnCallback, void *pvUser, ULONG fFlags);
     2443typedef  VOID    (NTAPI *PFNKEDEREGISTERPROCESSORCHANGECALLBACK)(PVOID pvCallback);
     2444typedef  NTSTATUS (NTAPI *PFNKESETTARGETPROCESSORDPCEX)(KDPC *pDpc, PROCESSOR_NUMBER *pProcNumber);
    24332445
    24342446NTSYSAPI BOOLEAN  NTAPI ObFindHandleForObject(PEPROCESS pProcess, PVOID pvObject, POBJECT_TYPE pObjectType,
  • trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp

    r62477 r64234  
    3333#include <iprt/assert.h>
    3434#include <iprt/err.h>
     35#include <iprt/mem.h>
    3536#include <iprt/mp.h>
    3637#include <iprt/string.h>
    3738#include "internal/initterm.h"
    3839#include "internal-r0drv-nt.h"
     40#include "../mp-r0drv.h"
    3941#include "symdb.h"
    4042#include "symdbdata.h"
     
    5153 * and update this variable as CPUs comes online. (The code is done already.)
    5254 */
    53 RTCPUSET                            g_rtMpNtCpuSet;
     55RTCPUSET                                g_rtMpNtCpuSet;
     56/** Maximum number of processor groups. */
     57uint32_t                                g_cRtMpNtMaxGroups;
     58/** Maximum number of processors. */
     59uint32_t                                g_cRtMpNtMaxCpus;
     60/** The handle of the rtR0NtMpProcessorChangeCallback registration. */
     61static PVOID                            g_pvMpCpuChangeCallback = NULL;
    5462
    5563/** ExSetTimerResolution, introduced in W2K. */
    56 PFNMYEXSETTIMERRESOLUTION           g_pfnrtNtExSetTimerResolution;
     64PFNMYEXSETTIMERRESOLUTION               g_pfnrtNtExSetTimerResolution;
    5765/** KeFlushQueuedDpcs, introduced in XP. */
    58 PFNMYKEFLUSHQUEUEDDPCS              g_pfnrtNtKeFlushQueuedDpcs;
     66PFNMYKEFLUSHQUEUEDDPCS                  g_pfnrtNtKeFlushQueuedDpcs;
    5967/** HalRequestIpi, version introduced with windows 7. */
    60 PFNHALREQUESTIPI_W7PLUS             g_pfnrtHalRequestIpiW7Plus;
     68PFNHALREQUESTIPI_W7PLUS                 g_pfnrtHalRequestIpiW7Plus;
    6169/** HalRequestIpi, version valid up to windows vista?? */
    62 PFNHALREQUESTIPI_PRE_W7             g_pfnrtHalRequestIpiPreW7;
     70PFNHALREQUESTIPI_PRE_W7                 g_pfnrtHalRequestIpiPreW7;
    6371/** Worker for RTMpPokeCpu. */
    64 PFNRTSENDIPI                        g_pfnrtMpPokeCpuWorker;
     72PFNRTSENDIPI                            g_pfnrtMpPokeCpuWorker;
    6573/** KeIpiGenericCall - Introduced in Windows Server 2003. */
    66 PFNRTKEIPIGENERICCALL               g_pfnrtKeIpiGenericCall;
     74PFNRTKEIPIGENERICCALL                   g_pfnrtKeIpiGenericCall;
     75/** KeSetTargetProcessorDpcEx - Introduced in Windows 7. */
     76PFNKESETTARGETPROCESSORDPCEX            g_pfnrtKeSetTargetProcessorDpcEx;
    6777/** KeInitializeAffinityEx - Introducted in Windows 7. */
    68 PFNKEINITIALIZEAFFINITYEX           g_pfnrtKeInitializeAffinityEx;
     78PFNKEINITIALIZEAFFINITYEX               g_pfnrtKeInitializeAffinityEx;
    6979/** KeAddProcessorAffinityEx - Introducted in Windows 7. */
    70 PFNKEADDPROCESSORAFFINITYEX         g_pfnrtKeAddProcessorAffinityEx;
    71 /** KeGetProcessorIndexFromNumber - Introducted in Windows  7. */
    72 PFNKEGETPROCESSORINDEXFROMNUMBER    g_pfnrtKeGetProcessorIndexFromNumber;
     80PFNKEADDPROCESSORAFFINITYEX             g_pfnrtKeAddProcessorAffinityEx;
     81/** KeGetProcessorIndexFromNumber - Introducted in Windows 7. */
     82PFNKEGETPROCESSORINDEXFROMNUMBER        g_pfnrtKeGetProcessorIndexFromNumber;
     83/** KeGetProcessorNumberFromIndex - Introducted in Windows 7. */
     84PFNKEGETPROCESSORNUMBERFROMINDEX        g_pfnrtKeGetProcessorNumberFromIndex;
     85/** KeGetCurrentProcessorNumberEx - Introducted in Windows 7. */
     86PFNKEGETCURRENTPROCESSORNUMBEREX        g_pfnrtKeGetCurrentProcessorNumberEx;
     87/** KeQueryActiveProcessors - Introducted in Windows 2000. */
     88PFNKEQUERYACTIVEPROCESSORS              g_pfnrtKeQueryActiveProcessors;
     89/** KeQueryMaximumProcessorCount   - Introducted in Vista and obsoleted W7. */
     90PFNKEQUERYMAXIMUMPROCESSORCOUNT         g_pfnrtKeQueryMaximumProcessorCount;
     91/** KeQueryMaximumProcessorCountEx - Introducted in Windows 7. */
     92PFNKEQUERYMAXIMUMPROCESSORCOUNTEX       g_pfnrtKeQueryMaximumProcessorCountEx;
     93/** KeQueryMaximumGroupCount - Introducted in Windows 7. */
     94PFNKEQUERYMAXIMUMGROUPCOUNT             g_pfnrtKeQueryMaximumGroupCount;
     95/** KeQueryLogicalProcessorRelationship - Introducted in Windows 7. */
     96PFNKEQUERYLOGICALPROCESSORRELATIONSHIP  g_pfnrtKeQueryLogicalProcessorRelationship;
     97/** KeRegisterProcessorChangeCallback - Introducted in Windows 7. */
     98PFNKEREGISTERPROCESSORCHANGECALLBACK    g_pfnrtKeRegisterProcessorChangeCallback;
     99/** KeDeregisterProcessorChangeCallback - Introducted in Windows 7. */
     100PFNKEDEREGISTERPROCESSORCHANGECALLBACK  g_pfnrtKeDeregisterProcessorChangeCallback;
    73101/** RtlGetVersion, introduced in ??. */
    74 PFNRTRTLGETVERSION                  g_pfnrtRtlGetVersion;
     102PFNRTRTLGETVERSION                      g_pfnrtRtlGetVersion;
    75103#ifndef RT_ARCH_AMD64
    76104/** KeQueryInterruptTime - exported/new in Windows 2000. */
    77 PFNRTKEQUERYINTERRUPTTIME           g_pfnrtKeQueryInterruptTime;
     105PFNRTKEQUERYINTERRUPTTIME               g_pfnrtKeQueryInterruptTime;
    78106/** KeQuerySystemTime - exported/new in Windows 2000. */
    79 PFNRTKEQUERYSYSTEMTIME              g_pfnrtKeQuerySystemTime;
     107PFNRTKEQUERYSYSTEMTIME                  g_pfnrtKeQuerySystemTime;
    80108#endif
    81109/** KeQueryInterruptTimePrecise - new in Windows 8. */
    82 PFNRTKEQUERYINTERRUPTTIMEPRECISE    g_pfnrtKeQueryInterruptTimePrecise;
     110PFNRTKEQUERYINTERRUPTTIMEPRECISE        g_pfnrtKeQueryInterruptTimePrecise;
    83111/** KeQuerySystemTimePrecise - new in Windows 8. */
    84 PFNRTKEQUERYSYSTEMTIMEPRECISE       g_pfnrtKeQuerySystemTimePrecise;
     112PFNRTKEQUERYSYSTEMTIMEPRECISE           g_pfnrtKeQuerySystemTimePrecise;
    85113
    86114/** Offset of the _KPRCB::QuantumEnd field. 0 if not found. */
    87 uint32_t                            g_offrtNtPbQuantumEnd;
     115uint32_t                                g_offrtNtPbQuantumEnd;
    88116/** Size of the _KPRCB::QuantumEnd field. 0 if not found. */
    89 uint32_t                            g_cbrtNtPbQuantumEnd;
     117uint32_t                                g_cbrtNtPbQuantumEnd;
    90118/** Offset of the _KPRCB::DpcQueueDepth field. 0 if not found. */
    91 uint32_t                            g_offrtNtPbDpcQueueDepth;
     119uint32_t                                g_offrtNtPbDpcQueueDepth;
    92120
    93121
     
    125153
    126154    /* Note! We cannot quite say if something is MP or UNI. So, fSmp is
    127              redefined to indicate that it must be MP. */
    128     pOsVerInfo->fSmp        = RTMpGetCount() >  1
    129                            || ulMajorVersion >= 6; /* Vista and later has no UNI kernel AFAIK. */
     155             redefined to indicate that it must be MP.
     156       Note! RTMpGetCount is not available here. */
     157    pOsVerInfo->fSmp = ulMajorVersion >= 6; /* Vista and later has no UNI kernel AFAIK. */
     158    if (!pOsVerInfo->fSmp)
     159    {
     160        if (   g_pfnrtKeQueryMaximumProcessorCountEx
     161            && g_pfnrtKeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS) > 1)
     162            pOsVerInfo->fSmp = true;
     163        else if (   g_pfnrtKeQueryMaximumProcessorCount
     164                 && g_pfnrtKeQueryMaximumProcessorCount() > 1)
     165            pOsVerInfo->fSmp = true;
     166        else if (   g_pfnrtKeQueryActiveProcessors
     167                 && g_pfnrtKeQueryActiveProcessors() > 1)
     168            pOsVerInfo->fSmp = true;
     169        else if (KeNumberProcessors > 1)
     170            pOsVerInfo->fSmp = true;
     171    }
    130172}
    131173
     
    203245
    204246
     247/**
     248 * Implements the NT PROCESSOR_CALLBACK_FUNCTION callback function.
     249 *
     250 * This maintains the g_rtMpNtCpuSet and works MP notification callbacks.  When
     251 * registered, it's called for each active CPU in the system, avoiding racing
     252 * CPU hotplugging (as well as testing the callback).
     253 *
     254 * @param   pvUser              User context (not used).
     255 * @param   pChangeCtx          Change context (in).
     256 * @param   prcOperationStatus  Operation status (in/out).
     257 */
     258static VOID __stdcall rtR0NtMpProcessorChangeCallback(void *pvUser, PKE_PROCESSOR_CHANGE_NOTIFY_CONTEXT pChangeCtx,
     259                                                      PNTSTATUS prcOperationStatus)
     260{
     261    RT_NOREF(pvUser, prcOperationStatus);
     262    switch (pChangeCtx->State)
     263    {
     264        case KeProcessorAddCompleteNotify:
     265            if (pChangeCtx->NtNumber < RTCPUSET_MAX_CPUS)
     266            {
     267                RTCpuSetAddByIndex(&g_rtMpNtCpuSet, pChangeCtx->NtNumber);
     268                rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, pChangeCtx->NtNumber);
     269            }
     270            else
     271            {
     272                DbgPrint("rtR0NtMpProcessorChangeCallback: NtNumber=%u (%#x) is higher than RTCPUSET_MAX_CPUS (%d)\n",
     273                         pChangeCtx->NtNumber, pChangeCtx->NtNumber, RTCPUSET_MAX_CPUS);
     274                AssertMsgFailed(("NtNumber=%u (%#x)\n", pChangeCtx->NtNumber, pChangeCtx->NtNumber));
     275            }
     276            break;
     277
     278        case KeProcessorAddStartNotify:
     279        case KeProcessorAddFailureNotify:
     280            /* ignore */
     281            break;
     282
     283        default:
     284            AssertMsgFailed(("State=%u\n", pChangeCtx->State));
     285    }
     286}
     287
     288
     289/**
     290 * Wrapper around KeQueryLogicalProcessorRelationship.
     291 *
     292 * @returns IPRT status code.
     293 * @param   ppInfo  Where to return the info. Pass to RTMemFree when done.
     294 */
     295static int rtR0NtInitQueryGroupRelations(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **ppInfo)
     296{
     297    ULONG    cbInfo = sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)
     298                    + g_cRtMpNtMaxGroups * sizeof(GROUP_RELATIONSHIP);
     299    NTSTATUS rcNt;
     300    do
     301    {
     302        SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)RTMemAlloc(cbInfo);
     303        if (pInfo)
     304        {
     305            rcNt = g_pfnrtKeQueryLogicalProcessorRelationship(NULL /*pProcNumber*/, RelationGroup, pInfo, &cbInfo);
     306            if (NT_SUCCESS(rcNt))
     307            {
     308                *ppInfo = pInfo;
     309                return VINF_SUCCESS;
     310            }
     311
     312            RTMemFree(pInfo);
     313            pInfo = NULL;
     314        }
     315        else
     316            rcNt = STATUS_NO_MEMORY;
     317    } while (rcNt == STATUS_INFO_LENGTH_MISMATCH);
     318    DbgPrint("IPRT: Fatal: KeQueryLogicalProcessorRelationship failed: %#x\n", rcNt);
     319    AssertMsgFailed(("KeQueryLogicalProcessorRelationship failed: %#x\n", rcNt));
     320    return RTErrConvertFromNtStatus(rcNt);
     321}
     322
     323
     324/**
     325 * Initalizes multiprocessor globals.
     326 *
     327 * @returns IPRT status code.
     328 */
     329static int rtR0NtInitMp(RTNTSDBOSVER const *pOsVerInfo)
     330{
     331#define MY_CHECK_BREAK(a_Check, a_DbgPrintArgs) \
     332        AssertMsgBreakStmt(a_Check, a_DbgPrintArgs, DbgPrint a_DbgPrintArgs; rc = VERR_INTERNAL_ERROR_4 )
     333#define MY_CHECK_RETURN(a_Check, a_DbgPrintArgs, a_rcRet) \
     334        AssertMsgReturnStmt(a_Check, a_DbgPrintArgs, DbgPrint a_DbgPrintArgs, a_rcRet)
     335#define MY_CHECK(a_Check, a_DbgPrintArgs) \
     336        AssertMsgStmt(a_Check, a_DbgPrintArgs, DbgPrint a_DbgPrintArgs; rc = VERR_INTERNAL_ERROR_4 )
     337
     338    /*
     339     * API combination checks.
     340     */
     341    MY_CHECK_RETURN(!g_pfnrtKeSetTargetProcessorDpcEx || g_pfnrtKeGetProcessorNumberFromIndex,
     342                    ("IPRT: Fatal: Missing KeSetTargetProcessorDpcEx without KeGetProcessorNumberFromIndex!\n"),
     343                    VERR_SYMBOL_NOT_FOUND);
     344
     345    /*
     346     * Get max number of processor groups.
     347     */
     348    if (g_pfnrtKeQueryMaximumGroupCount)
     349    {
     350        g_cRtMpNtMaxGroups = g_pfnrtKeQueryMaximumGroupCount();
     351        MY_CHECK_RETURN(g_cRtMpNtMaxGroups <= RTCPUSET_MAX_CPUS && g_cRtMpNtMaxGroups > 0,
     352                        ("IPRT: Fatal: g_cRtMpNtMaxGroups=%u, max %u\n", g_cRtMpNtMaxGroups, RTCPUSET_MAX_CPUS),
     353                        VERR_MP_TOO_MANY_CPUS);
     354    }
     355    else
     356        g_cRtMpNtMaxGroups = 1;
     357
     358    /*
     359     * Get max number CPUs.
     360     * This also defines the range of NT CPU indexes, RTCPUID and index into RTCPUSET.
     361     */
     362    if (g_pfnrtKeQueryMaximumProcessorCountEx)
     363    {
     364        g_cRtMpNtMaxCpus = g_pfnrtKeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
     365        MY_CHECK_RETURN(g_cRtMpNtMaxCpus <= RTCPUSET_MAX_CPUS && g_cRtMpNtMaxCpus > 0,
     366                        ("IPRT: Fatal: g_cRtMpNtMaxGroups=%u, max %u [KeQueryMaximumProcessorCountEx]\n",
     367                         g_cRtMpNtMaxGroups, RTCPUSET_MAX_CPUS),
     368                        VERR_MP_TOO_MANY_CPUS);
     369    }
     370    else if (g_pfnrtKeQueryMaximumProcessorCount)
     371    {
     372        g_cRtMpNtMaxCpus = g_pfnrtKeQueryMaximumProcessorCount();
     373        MY_CHECK_RETURN(g_cRtMpNtMaxCpus <= RTCPUSET_MAX_CPUS && g_cRtMpNtMaxCpus > 0,
     374                        ("IPRT: Fatal: g_cRtMpNtMaxGroups=%u, max %u [KeQueryMaximumProcessorCount]\n",
     375                         g_cRtMpNtMaxGroups, RTCPUSET_MAX_CPUS),
     376                        VERR_MP_TOO_MANY_CPUS);
     377    }
     378    else if (g_pfnrtKeQueryActiveProcessors)
     379    {
     380        KAFFINITY fActiveProcessors = g_pfnrtKeQueryActiveProcessors();
     381        MY_CHECK_RETURN(fActiveProcessors != 0,
     382                        ("IPRT: Fatal: KeQueryActiveProcessors returned 0!\n"),
     383                        VERR_INTERNAL_ERROR_2);
     384        g_cRtMpNtMaxCpus = 0;
     385        do
     386        {
     387            g_cRtMpNtMaxCpus++;
     388            fActiveProcessors >>= 1;
     389        } while (fActiveProcessors);
     390    }
     391    else
     392        g_cRtMpNtMaxCpus = KeNumberProcessors;
     393
     394    /*
     395     * Query the details for the groups to figure out which CPUs are online as
     396     * well as the NT index limit.
     397     */
     398    if (g_pfnrtKeQueryLogicalProcessorRelationship)
     399    {
     400        MY_CHECK_RETURN(g_pfnrtKeGetProcessorIndexFromNumber,
     401                        ("IPRT: Fatal: Found KeQueryLogicalProcessorRelationship but not KeGetProcessorIndexFromNumber!\n"),
     402                        VERR_SYMBOL_NOT_FOUND);
     403        MY_CHECK_RETURN(g_pfnrtKeGetProcessorNumberFromIndex,
     404                        ("IPRT: Fatal: Found KeQueryLogicalProcessorRelationship but not KeGetProcessorIndexFromNumber!\n"),
     405                        VERR_SYMBOL_NOT_FOUND);
     406        MY_CHECK_RETURN(g_pfnrtKeSetTargetProcessorDpcEx,
     407                        ("IPRT: Fatal: Found KeQueryLogicalProcessorRelationship but not KeSetTargetProcessorDpcEx!\n"),
     408                        VERR_SYMBOL_NOT_FOUND);
     409
     410        SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pInfo = NULL;
     411        int rc = rtR0NtInitQueryGroupRelations(&pInfo);
     412        if (RT_FAILURE(rc))
     413            return rc;
     414
     415        AssertReturnStmt(pInfo->Group.MaximumGroupCount == g_cRtMpNtMaxGroups, RTMemFree(pInfo), VERR_INTERNAL_ERROR_3);
     416
     417        /*
     418         * Calc online mask.
     419         *
     420         * Also check ASSUMPTIONS:
     421         *      - Processor indexes going to KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS)
     422         *      - Processor indexes being assigned to absent hotswappable CPUs, i.e.
     423         *        KeGetProcessorIndexFromNumber and KeGetProcessorNumberFromIndex works
     424         *        all possible indexes. [Not yet confirmed!]
     425         *      - Processor indexes are assigned in group order.
     426         *      - MaximumProcessorCount specifies the highest bit in the active mask.
     427         *        This is for confirming process IDs assigned by IPRT in ring-3.
     428         */
     429        /** @todo Test the latter on a real/virtual system. */
     430        RTCpuSetEmpty(&g_rtMpNtCpuSet);
     431        uint32_t idxCpuExpect = 0;
     432        for (uint32_t idxGroup = 0; RT_SUCCESS(rc) && idxGroup < pInfo->Group.ActiveGroupCount; idxGroup++)
     433        {
     434            const PROCESSOR_GROUP_INFO *pGrpInfo = &pInfo->Group.GroupInfo[idxGroup];
     435            MY_CHECK_BREAK(pGrpInfo->MaximumProcessorCount <= MAXIMUM_PROC_PER_GROUP,
     436                           ("IPRT: Fatal: MaximumProcessorCount=%u\n", pGrpInfo->MaximumProcessorCount));
     437            MY_CHECK_BREAK(pGrpInfo->ActiveProcessorCount <= MAXIMUM_PROC_PER_GROUP,
     438                           ("IPRT: Fatal: ActiveProcessorCount=%u\n", pGrpInfo->ActiveProcessorCount));
     439            MY_CHECK_BREAK(pGrpInfo->ActiveProcessorCount <= pGrpInfo->MaximumProcessorCount,
     440                           ("IPRT: Fatal: ActiveProcessorCount=%u > MaximumProcessorCount=%u\n",
     441                            pGrpInfo->ActiveProcessorCount, pGrpInfo->MaximumProcessorCount));
     442            for (uint32_t idxMember = 0; idxMember < pGrpInfo->MaximumProcessorCount; idxMember++, idxCpuExpect++)
     443            {
     444                PROCESSOR_NUMBER ProcNum;
     445                ProcNum.Group    = (USHORT)idxGroup;
     446                ProcNum.Number   = (UCHAR)idxMember;
     447                ProcNum.Reserved = 0;
     448                ULONG idxCpu = g_pfnrtKeGetProcessorIndexFromNumber(&ProcNum);
     449                MY_CHECK_BREAK(idxCpu != INVALID_PROCESSOR_INDEX,
     450                               ("IPRT: Fatal: KeGetProcessorIndexFromNumber(%u/%u) failed\n", idxGroup, idxMember));
     451                MY_CHECK_BREAK(idxCpu < g_cRtMpNtMaxCpus && idxCpu < RTCPUSET_MAX_CPUS,
     452                               ("IPRT: Fatal: idxCpu=%u >= g_cRtMpNtMaxCpu=%u (RTCPUSET_MAX_CPUS=%u)\n",
     453                                idxCpu, g_cRtMpNtMaxCpus, RTCPUSET_MAX_CPUS));
     454                MY_CHECK_BREAK(idxCpu == idxCpuExpect, ("IPRT: Fatal: idxCpu=%u != idxCpuExpect=%u\n", idxCpu, idxCpuExpect));
     455
     456                ProcNum.Group    = UINT16_MAX;
     457                ProcNum.Number   = UINT8_MAX;
     458                ProcNum.Reserved = UINT8_MAX;
     459                NTSTATUS rcNt = g_pfnrtKeGetProcessorNumberFromIndex(idxCpu, &ProcNum);
     460                MY_CHECK_BREAK(NT_SUCCESS(rcNt), ("IPRT: Fatal: KeGetProcessorNumberFromIndex(%u,) -> %#x!\n", idxCpu, rcNt));
     461                MY_CHECK_BREAK(ProcNum.Group == idxGroup && ProcNum.Number == idxMember,
     462                               ("IPRT: Fatal: KeGetProcessorXxxxFromYyyy roundtrip error for %#x! Group: %u vs %u, Number: %u vs %u\n",
     463                                idxCpu, ProcNum.Group, idxGroup, ProcNum.Number, idxMember));
     464
     465                if (pGrpInfo->ActiveProcessorMask & RT_BIT_64(idxMember))
     466                    RTCpuSetAddByIndex(&g_rtMpNtCpuSet, idxCpu);
     467            }
     468        }
     469        RTMemFree(pInfo);
     470        if (RT_FAILURE(rc)) /* MY_CHECK_BREAK sets rc. */
     471            return rc;
     472    }
     473    else
     474    {
     475        /* Legacy: */
     476        MY_CHECK_RETURN(g_cRtMpNtMaxGroups == 1, ("IPRT: Fatal: Missing KeQueryLogicalProcessorRelationship!\n"),
     477                        VERR_SYMBOL_NOT_FOUND);
     478
     479        if (g_pfnrtKeQueryActiveProcessors)
     480            RTCpuSetFromU64(&g_rtMpNtCpuSet, g_pfnrtKeQueryActiveProcessors());
     481        else if (g_cRtMpNtMaxCpus < 64)
     482            RTCpuSetFromU64(&g_rtMpNtCpuSet, (UINT64_C(1) << g_cRtMpNtMaxCpus) - 1);
     483        else
     484        {
     485            MY_CHECK_RETURN(g_cRtMpNtMaxCpus == 64, ("IPRT: Fatal: g_cRtMpNtMaxCpus=%u, expect 64 or less\n", g_cRtMpNtMaxCpus),
     486                            VERR_MP_TOO_MANY_CPUS);
     487            RTCpuSetFromU64(&g_rtMpNtCpuSet, UINT64_MAX);
     488        }
     489    }
     490
     491    /*
     492     * Register CPU hot plugging callback.
     493     */
     494    Assert(g_pvMpCpuChangeCallback == NULL);
     495    if (g_pfnrtKeRegisterProcessorChangeCallback)
     496    {
     497        MY_CHECK_RETURN(g_pfnrtKeDeregisterProcessorChangeCallback,
     498                        ("IPRT: Fatal: KeRegisterProcessorChangeCallback without KeDeregisterProcessorChangeCallback!\n"),
     499                        VERR_SYMBOL_NOT_FOUND);
     500
     501        RTCPUSET ActiveSetCopy = g_rtMpNtCpuSet;
     502        RTCpuSetEmpty(&g_rtMpNtCpuSet);
     503        g_pvMpCpuChangeCallback = g_pfnrtKeRegisterProcessorChangeCallback(rtR0NtMpProcessorChangeCallback, NULL /*pvUser*/,
     504                                                                           KE_PROCESSOR_CHANGE_ADD_EXISTING);
     505        if (!g_pvMpCpuChangeCallback) 
     506        {
     507            AssertFailed();
     508            g_rtMpNtCpuSet = ActiveSetCopy;
     509        }
     510    }
     511
     512    /*
     513     * Special IPI fun for RTMpPokeCpu.
     514     *
     515     * On Vista and later the DPC method doesn't seem to reliably send IPIs,
     516     * so we have to use alternative methods.
     517     *
     518     * On AMD64 We used to use the HalSendSoftwareInterrupt API (also x86 on
     519     * W10+), it looks faster and more convenient to use, however we're either
     520     * using it wrong or it doesn't reliably do what we want (see @bugref{8343}).
     521     *
     522     * The HalRequestIpip API is thus far the only alternative to KeInsertQueueDpc
     523     * for doing targetted IPIs.  Trouble with this API is that it changed
     524     * fundamentally in Window 7 when they added support for lots of processors.
     525     *
     526     * If we really think we cannot use KeInsertQueueDpc, we use the broadcast IPI
     527     * API KeIpiGenericCall.
     528     */
     529    if (   pOsVerInfo->uMajorVer > 6
     530        || (pOsVerInfo->uMajorVer == 6 && pOsVerInfo->uMinorVer > 0))
     531        g_pfnrtHalRequestIpiPreW7 = NULL;
     532    else
     533        g_pfnrtHalRequestIpiW7Plus = NULL;
     534
     535    g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingDpc;
     536#ifndef IPRT_TARGET_NT4
     537    if (   g_pfnrtHalRequestIpiW7Plus
     538        && g_pfnrtKeInitializeAffinityEx
     539        && g_pfnrtKeAddProcessorAffinityEx
     540        && g_pfnrtKeGetProcessorIndexFromNumber)
     541    {
     542        DbgPrint("IPRT: RTMpPoke => rtMpPokeCpuUsingHalReqestIpiW7Plus\n");
     543        g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalReqestIpiW7Plus;
     544    }
     545    else if (pOsVerInfo->uMajorVer >= 6 && g_pfnrtKeIpiGenericCall)
     546    {
     547        DbgPrint("IPRT: RTMpPoke => rtMpPokeCpuUsingBroadcastIpi\n");
     548        g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingBroadcastIpi;
     549    }
     550    else
     551        DbgPrint("IPRT: RTMpPoke => rtMpPokeCpuUsingDpc\n");
     552    /* else: Windows XP should send always send an IPI -> VERIFY */
     553#endif
     554
     555    return VINF_SUCCESS;
     556}
     557
     558
    205559DECLHIDDEN(int) rtR0InitNative(void)
    206560{
    207561    /*
    208      * Init the Nt cpu set.
     562     * Initialize the function pointers.
    209563     */
    210564#ifdef IPRT_TARGET_NT4
    211     KAFFINITY ActiveProcessors = (UINT64_C(1) << KeNumberProcessors) - UINT64_C(1);
     565# define GET_SYSTEM_ROUTINE_EX(a_Prf, a_Name, a_pfnType) do { RT_CONCAT3(g_pfnrt, a_Prf, a_Name) = NULL; } while (0)
    212566#else
    213     KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
     567    UNICODE_STRING RoutineName;
     568# define GET_SYSTEM_ROUTINE_EX(a_Prf, a_Name, a_pfnType) \
     569    do { \
     570        RtlInitUnicodeString(&RoutineName, L#a_Name); \
     571        RT_CONCAT3(g_pfnrt, a_Prf, a_Name) = (a_pfnType)MmGetSystemRoutineAddress(&RoutineName); \
     572    } while (0)
    214573#endif
    215     RTCpuSetEmpty(&g_rtMpNtCpuSet);
    216     RTCpuSetFromU64(&g_rtMpNtCpuSet, ActiveProcessors);
    217 /** @todo Port to W2K8 with > 64 cpus/threads. */
    218 
    219     /*
    220      * Initialize the function pointers.
    221      */
     574#define GET_SYSTEM_ROUTINE(a_Name)                 GET_SYSTEM_ROUTINE_EX(RT_NOTHING, a_Name, decltype(a_Name) *)
     575#define GET_SYSTEM_ROUTINE_PRF(a_Prf,a_Name)       GET_SYSTEM_ROUTINE_EX(a_Prf, a_Name, decltype(a_Name) *)
     576#define GET_SYSTEM_ROUTINE_TYPE(a_Name, a_pfnType) GET_SYSTEM_ROUTINE_EX(RT_NOTHING, a_Name, a_pfnType)
     577
     578    GET_SYSTEM_ROUTINE_PRF(Nt,ExSetTimerResolution);
     579    GET_SYSTEM_ROUTINE_PRF(Nt,KeFlushQueuedDpcs);
     580    GET_SYSTEM_ROUTINE(KeIpiGenericCall);
     581    GET_SYSTEM_ROUTINE(KeSetTargetProcessorDpcEx);
     582    GET_SYSTEM_ROUTINE(KeInitializeAffinityEx);
     583    GET_SYSTEM_ROUTINE(KeAddProcessorAffinityEx);
     584    GET_SYSTEM_ROUTINE_TYPE(KeGetProcessorIndexFromNumber, PFNKEGETPROCESSORINDEXFROMNUMBER);
     585    GET_SYSTEM_ROUTINE(KeGetProcessorNumberFromIndex);
     586    GET_SYSTEM_ROUTINE_TYPE(KeGetCurrentProcessorNumberEx, PFNKEGETCURRENTPROCESSORNUMBEREX);
     587    GET_SYSTEM_ROUTINE(KeQueryActiveProcessors);
     588    GET_SYSTEM_ROUTINE(KeQueryMaximumProcessorCount);
     589    GET_SYSTEM_ROUTINE(KeQueryMaximumProcessorCountEx);
     590    GET_SYSTEM_ROUTINE(KeQueryMaximumGroupCount);
     591    GET_SYSTEM_ROUTINE(KeQueryLogicalProcessorRelationship);
     592    GET_SYSTEM_ROUTINE(KeRegisterProcessorChangeCallback);
     593    GET_SYSTEM_ROUTINE(KeDeregisterProcessorChangeCallback);
     594
     595    GET_SYSTEM_ROUTINE_TYPE(RtlGetVersion, PFNRTRTLGETVERSION);
     596#ifndef RT_ARCH_AMD64
     597    GET_SYSTEM_ROUTINE(KeQueryInterruptTime);
     598    GET_SYSTEM_ROUTINE(KeQuerySystemTime);
     599#endif
     600    GET_SYSTEM_ROUTINE_TYPE(KeQueryInterruptTimePrecise, PFNRTKEQUERYINTERRUPTTIMEPRECISE);
     601    GET_SYSTEM_ROUTINE_TYPE(KeQuerySystemTimePrecise, PFNRTKEQUERYSYSTEMTIMEPRECISE);
     602
    222603#ifdef IPRT_TARGET_NT4
    223     g_pfnrtNtExSetTimerResolution = NULL;
    224     g_pfnrtNtKeFlushQueuedDpcs = NULL;
    225604    g_pfnrtHalRequestIpiW7Plus = NULL;
    226605    g_pfnrtHalRequestIpiPreW7 = NULL;
    227     g_pfnrtKeIpiGenericCall = NULL;
    228     g_pfnrtKeInitializeAffinityEx = NULL;
    229     g_pfnrtKeAddProcessorAffinityEx = NULL;
    230     g_pfnrtKeGetProcessorIndexFromNumber = NULL;
    231     g_pfnrtRtlGetVersion = NULL;
    232     g_pfnrtKeQueryInterruptTime = NULL;
    233     g_pfnrtKeQueryInterruptTimePrecise = NULL;
    234     g_pfnrtKeQuerySystemTime = NULL;
    235     g_pfnrtKeQuerySystemTimePrecise = NULL;
    236606#else
    237     UNICODE_STRING RoutineName;
    238     RtlInitUnicodeString(&RoutineName, L"ExSetTimerResolution");
    239     g_pfnrtNtExSetTimerResolution = (PFNMYEXSETTIMERRESOLUTION)MmGetSystemRoutineAddress(&RoutineName);
    240 
    241     RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs");
    242     g_pfnrtNtKeFlushQueuedDpcs = (PFNMYKEFLUSHQUEUEDDPCS)MmGetSystemRoutineAddress(&RoutineName);
    243 
    244607    RtlInitUnicodeString(&RoutineName, L"HalRequestIpi");
    245608    g_pfnrtHalRequestIpiW7Plus = (PFNHALREQUESTIPI_W7PLUS)MmGetSystemRoutineAddress(&RoutineName);
    246609    g_pfnrtHalRequestIpiPreW7 = (PFNHALREQUESTIPI_PRE_W7)g_pfnrtHalRequestIpiW7Plus;
    247 
    248     RtlInitUnicodeString(&RoutineName, L"KeIpiGenericCall");
    249     g_pfnrtKeIpiGenericCall = (PFNRTKEIPIGENERICCALL)MmGetSystemRoutineAddress(&RoutineName);
    250 
    251     RtlInitUnicodeString(&RoutineName, L"KeInitializeAffinityEx");
    252     g_pfnrtKeInitializeAffinityEx = (PFNKEINITIALIZEAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName);
    253 
    254     RtlInitUnicodeString(&RoutineName, L"KeAddProcessorAffinityEx");
    255     g_pfnrtKeAddProcessorAffinityEx = (PFNKEADDPROCESSORAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName);
    256 
    257     RtlInitUnicodeString(&RoutineName, L"KeGetProcessorIndexFromNumber");
    258     g_pfnrtKeGetProcessorIndexFromNumber = (PFNKEGETPROCESSORINDEXFROMNUMBER)MmGetSystemRoutineAddress(&RoutineName);
    259 
    260     RtlInitUnicodeString(&RoutineName, L"RtlGetVersion");
    261     g_pfnrtRtlGetVersion = (PFNRTRTLGETVERSION)MmGetSystemRoutineAddress(&RoutineName);
    262 # ifndef RT_ARCH_AMD64
    263     RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTime");
    264     g_pfnrtKeQueryInterruptTime = (PFNRTKEQUERYINTERRUPTTIME)MmGetSystemRoutineAddress(&RoutineName);
    265 
    266     RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTime");
    267     g_pfnrtKeQuerySystemTime = (PFNRTKEQUERYSYSTEMTIME)MmGetSystemRoutineAddress(&RoutineName);
    268 # endif
    269     RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTimePrecise");
    270     g_pfnrtKeQueryInterruptTimePrecise = (PFNRTKEQUERYINTERRUPTTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName);
    271 
    272     RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTimePrecise");
    273     g_pfnrtKeQuerySystemTimePrecise = (PFNRTKEQUERYSYSTEMTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName);
    274610#endif
    275611
     
    403739
    404740    /*
    405      * Special IPI fun for RTMpPokeCpu.
    406      *
    407      * On Vista and later the DPC method doesn't seem to reliably send IPIs,
    408      * so we have to use alternative methods.
    409      *
    410      * On AMD64 We used to use the HalSendSoftwareInterrupt API (also x86 on
    411      * W10+), it looks faster and more convenient to use, however we're either
    412      * using it wrong or it doesn't reliably do what we want (see @bugref{8343}).
    413      *
    414      * The HalRequestIpip API is thus far the only alternative to KeInsertQueueDpc
    415      * for doing targetted IPIs.  Trouble with this API is that it changed
    416      * fundamentally in Window 7 when they added support for lots of processors.
    417      *
    418      * If we really think we cannot use KeInsertQueueDpc, we use the broadcast IPI
    419      * API KeIpiGenericCall.
    420      */
    421     if (   OsVerInfo.uMajorVer > 6
    422         || (OsVerInfo.uMajorVer == 6 && OsVerInfo.uMinorVer > 0))
    423         g_pfnrtHalRequestIpiPreW7 = NULL;
    424     else
    425         g_pfnrtHalRequestIpiW7Plus = NULL;
    426 
    427     g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingDpc;
    428 #ifndef IPRT_TARGET_NT4
    429     if (   g_pfnrtHalRequestIpiW7Plus
    430         && g_pfnrtKeInitializeAffinityEx
    431         && g_pfnrtKeAddProcessorAffinityEx
    432         && g_pfnrtKeGetProcessorIndexFromNumber)
    433     {
    434         DbgPrint("IPRT: RTMpPoke => rtMpPokeCpuUsingHalReqestIpiW7Plus\n");
    435         g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalReqestIpiW7Plus;
    436     }
    437     else if (OsVerInfo.uMajorVer >= 6 && g_pfnrtKeIpiGenericCall)
    438     {
    439         DbgPrint("IPRT: RTMpPoke => rtMpPokeCpuUsingBroadcastIpi\n");
    440         g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingBroadcastIpi;
    441     }
    442     else
    443         DbgPrint("IPRT: RTMpPoke => rtMpPokeCpuUsingDpc\n");
    444     /* else: Windows XP should send always send an IPI -> VERIFY */
    445 #endif
     741     * Initialize multi processor stuff.  This registers a callback, so
     742     * we call rtR0TermNative to do the deregistration on failure.
     743     */
     744    int rc = rtR0NtInitMp(&OsVerInfo);
     745    if (RT_FAILURE(rc))
     746    {
     747        rtR0TermNative();
     748        DbgPrint("IPRT: Fatal: rtR0NtInitMp failed: %d\n", rc);
     749        return rc;
     750    }
    446751
    447752    return VINF_SUCCESS;
     
    451756DECLHIDDEN(void) rtR0TermNative(void)
    452757{
     758    /*
     759     * Deregister the processor change callback.
     760     */
     761    PVOID pvMpCpuChangeCallback = g_pvMpCpuChangeCallback;
     762    g_pvMpCpuChangeCallback = NULL;
     763    if (pvMpCpuChangeCallback)
     764    {
     765        AssertReturnVoid(g_pfnrtKeDeregisterProcessorChangeCallback);
     766        g_pfnrtKeDeregisterProcessorChangeCallback(pvMpCpuChangeCallback);
     767    }
    453768}
    454769
  • trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h

    r62477 r64234  
    5353*   Global Variables                                                           *
    5454*******************************************************************************/
    55 extern RTCPUSET                         g_rtMpNtCpuSet;
    56 extern PFNMYEXSETTIMERRESOLUTION        g_pfnrtNtExSetTimerResolution;
    57 extern PFNMYKEFLUSHQUEUEDDPCS           g_pfnrtNtKeFlushQueuedDpcs;
    58 extern PFNHALREQUESTIPI_W7PLUS          g_pfnrtHalRequestIpiW7Plus;
    59 extern PFNHALREQUESTIPI_PRE_W7          g_pfnrtHalRequestIpiPreW7;
    60 extern PFNHALSENDSOFTWAREINTERRUPT      g_pfnrtNtHalSendSoftwareInterrupt;
    61 extern PFNRTSENDIPI                     g_pfnrtMpPokeCpuWorker;
    62 extern PFNRTKEIPIGENERICCALL            g_pfnrtKeIpiGenericCall;
    63 extern PFNKEINITIALIZEAFFINITYEX        g_pfnrtKeInitializeAffinityEx;
    64 extern PFNKEADDPROCESSORAFFINITYEX      g_pfnrtKeAddProcessorAffinityEx;
    65 extern PFNKEGETPROCESSORINDEXFROMNUMBER g_pfnrtKeGetProcessorIndexFromNumber;
     55extern RTCPUSET                                g_rtMpNtCpuSet;
     56extern uint32_t                                g_cRtMpNtMaxGroups;
     57extern uint32_t                                g_cRtMpNtMaxCpus;
    6658
    67 extern PFNRTRTLGETVERSION               g_pfnrtRtlGetVersion;
     59extern PFNMYEXSETTIMERRESOLUTION               g_pfnrtNtExSetTimerResolution;
     60extern PFNMYKEFLUSHQUEUEDDPCS                  g_pfnrtNtKeFlushQueuedDpcs;
     61extern PFNHALREQUESTIPI_W7PLUS                 g_pfnrtHalRequestIpiW7Plus;
     62extern PFNHALREQUESTIPI_PRE_W7                 g_pfnrtHalRequestIpiPreW7;
     63extern PFNHALSENDSOFTWAREINTERRUPT             g_pfnrtNtHalSendSoftwareInterrupt;
     64extern PFNRTSENDIPI                            g_pfnrtMpPokeCpuWorker;
     65extern PFNRTKEIPIGENERICCALL                   g_pfnrtKeIpiGenericCall;
     66extern PFNKESETTARGETPROCESSORDPCEX            g_pfnrtKeSetTargetProcessorDpcEx;
     67extern PFNKEINITIALIZEAFFINITYEX               g_pfnrtKeInitializeAffinityEx;
     68extern PFNKEADDPROCESSORAFFINITYEX             g_pfnrtKeAddProcessorAffinityEx;
     69extern PFNKEGETPROCESSORINDEXFROMNUMBER        g_pfnrtKeGetProcessorIndexFromNumber;
     70extern PFNKEGETPROCESSORNUMBERFROMINDEX        g_pfnrtKeGetProcessorNumberFromIndex;
     71extern PFNKEGETCURRENTPROCESSORNUMBEREX        g_pfnrtKeGetCurrentProcessorNumberEx;
     72extern PFNKEQUERYACTIVEPROCESSORS              g_pfnrtKeQueryActiveProcessors;
     73extern PFNKEQUERYMAXIMUMPROCESSORCOUNT         g_pfnrtKeQueryMaximumProcessorCount;
     74extern PFNKEQUERYMAXIMUMPROCESSORCOUNTEX       g_pfnrtKeQueryMaximumProcessorCountEx;
     75extern PFNKEQUERYMAXIMUMGROUPCOUNT             g_pfnrtKeQueryMaximumGroupCount;
     76extern PFNKEQUERYLOGICALPROCESSORRELATIONSHIP  g_pfnrtKeQueryLogicalProcessorRelationship;
     77extern PFNKEREGISTERPROCESSORCHANGECALLBACK    g_pfnrtKeRegisterProcessorChangeCallback;
     78extern PFNKEDEREGISTERPROCESSORCHANGECALLBACK  g_pfnrtKeDeregisterProcessorChangeCallback;
     79extern PFNRTRTLGETVERSION                      g_pfnrtRtlGetVersion;
    6880#ifndef RT_ARCH_AMD64
    69 extern PFNRTKEQUERYINTERRUPTTIME        g_pfnrtKeQueryInterruptTime;
    70 extern PFNRTKEQUERYSYSTEMTIME           g_pfnrtKeQuerySystemTime;
     81extern PFNRTKEQUERYINTERRUPTTIME               g_pfnrtKeQueryInterruptTime;
     82extern PFNRTKEQUERYSYSTEMTIME                  g_pfnrtKeQuerySystemTime;
    7183#endif
    72 extern PFNRTKEQUERYINTERRUPTTIMEPRECISE g_pfnrtKeQueryInterruptTimePrecise;
    73 extern PFNRTKEQUERYSYSTEMTIMEPRECISE    g_pfnrtKeQuerySystemTimePrecise;
    74 extern uint32_t                         g_offrtNtPbQuantumEnd;
    75 extern uint32_t                         g_cbrtNtPbQuantumEnd;
    76 extern uint32_t                         g_offrtNtPbDpcQueueDepth;
     84extern PFNRTKEQUERYINTERRUPTTIMEPRECISE        g_pfnrtKeQueryInterruptTimePrecise;
     85extern PFNRTKEQUERYSYSTEMTIMEPRECISE           g_pfnrtKeQuerySystemTimePrecise;
     86
     87extern uint32_t                                g_offrtNtPbQuantumEnd;
     88extern uint32_t                                g_cbrtNtPbQuantumEnd;
     89extern uint32_t                                g_offrtNtPbDpcQueueDepth;
    7790
    7891
     
    8295int __stdcall rtMpPokeCpuUsingHalReqestIpiPreW7(RTCPUID idCpu);
    8396
     97DECLHIDDEN(int) rtMpNtSetTargetProcessorDpc(KDPC *pDpc, RTCPUID idCpu);
     98
    8499RT_C_DECLS_END
    85100
  • trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp

    r63063 r64234  
    7676
    7777
    78 /* test a couple of assumption. */
    79 AssertCompile(MAXIMUM_PROCESSORS <= RTCPUSET_MAX_CPUS);
    80 AssertCompile(NIL_RTCPUID >= MAXIMUM_PROCESSORS);
    81 
    82 /** @todo
    83  * We cannot do other than assume a 1:1 relationship between the
    84  * affinity mask and the process despite the vagueness/warnings in
    85  * the docs. If someone knows a better way to get this done, please
    86  * let bird know.
    87  */
    88 
    89 
    9078RTDECL(RTCPUID) RTMpCpuId(void)
    9179{
     80    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     81
     82    if (g_pfnrtKeGetCurrentProcessorNumberEx)
     83    {
     84        KEPROCESSORINDEX idxCpu = g_pfnrtKeGetCurrentProcessorNumberEx(NULL);
     85        Assert(idxCpu < RTCPUSET_MAX_CPUS);
     86        return idxCpu;
     87    }
     88
    9289    /* WDK upgrade warning: PCR->Number changed from BYTE to WORD. */
    9390    return KeGetCurrentProcessorNumber();
     
    9794RTDECL(int) RTMpCurSetIndex(void)
    9895{
    99     /* WDK upgrade warning: PCR->Number changed from BYTE to WORD. */
    100     return KeGetCurrentProcessorNumber();
     96    return (int)RTMpCpuId();
    10197}
    10298
     
    104100RTDECL(int) RTMpCurSetIndexAndId(PRTCPUID pidCpu)
    105101{
    106     return *pidCpu = KeGetCurrentProcessorNumber();
     102    return *pidCpu = RTMpCpuId();
    107103}
    108104
     
    110106RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
    111107{
    112     return idCpu < MAXIMUM_PROCESSORS ? (int)idCpu : -1;
     108    /* 1:1 mapping, just do range checks. */
     109    return idCpu < RTCPUSET_MAX_CPUS ? (int)idCpu : -1;
    113110}
    114111
     
    116113RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
    117114{
    118     return (unsigned)iCpu < MAXIMUM_PROCESSORS ? iCpu : NIL_RTCPUID;
     115    /* 1:1 mapping, just do range checks. */
     116    return (unsigned)iCpu < RTCPUSET_MAX_CPUS ? iCpu : NIL_RTCPUID;
    119117}
    120118
     
    122120RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
    123121{
    124     /** @todo use KeQueryMaximumProcessorCount on vista+ */
    125     return MAXIMUM_PROCESSORS - 1;
     122    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     123
     124    /* According to MSDN the processor indexes goes from 0 to the maximum
     125       number of CPUs in the system.  We've check this in initterm-r0drv-nt.cpp. */
     126    return g_cRtMpNtMaxCpus - 1;
    126127}
    127128
     
    129130RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
    130131{
    131     if (idCpu >= MAXIMUM_PROCESSORS)
    132         return false;
    133 
    134 #if 0 /* this isn't safe at all IRQLs (great work guys) */
    135     KAFFINITY Mask = KeQueryActiveProcessors();
    136     return !!(Mask & RT_BIT_64(idCpu));
    137 #else
    138     return RTCpuSetIsMember(&g_rtMpNtCpuSet, idCpu);
    139 #endif
     132    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     133    return idCpu < RTCPUSET_MAX_CPUS
     134        && RTCpuSetIsMember(&g_rtMpNtCpuSet, idCpu);
    140135}
    141136
     
    143138RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
    144139{
    145     /* Cannot easily distinguish between online and offline cpus. */
    146     /** @todo online/present cpu stuff must be corrected for proper W2K8 support
    147      *        (KeQueryMaximumProcessorCount). */
    148     return RTMpIsCpuOnline(idCpu);
     140    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     141
     142    /* A possible CPU ID is one with a value lower than g_cRtMpNtMaxCpus (see
     143       comment in RTMpGetMaxCpuId). */
     144    return idCpu < g_cRtMpNtMaxCpus;
    149145}
    150146
     
    153149RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
    154150{
    155     /** @todo online/present cpu stuff must be corrected for proper W2K8 support
    156      *        (KeQueryMaximumProcessorCount). */
    157     return RTMpGetOnlineSet(pSet);
     151    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     152
     153    /* The set of possible CPU IDs(/indexes) are from 0 up to
     154       g_cRtMpNtMaxCpus (see comment in RTMpGetMaxCpuId). */
     155    RTCpuSetEmpty(pSet);
     156    int idxCpu = g_cRtMpNtMaxCpus;
     157    while (idxCpu-- > 0)
     158        RTCpuSetAddByIndex(pSet, idxCpu);
     159    return pSet;
    158160}
    159161
     
    161163RTDECL(RTCPUID) RTMpGetCount(void)
    162164{
    163     /** @todo online/present cpu stuff must be corrected for proper W2K8 support
    164      *        (KeQueryMaximumProcessorCount). */
    165     return RTMpGetOnlineCount();
     165    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     166    return g_cRtMpNtMaxCpus;
    166167}
    167168
     
    169170RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
    170171{
    171 #if 0 /* this isn't safe at all IRQLs (great work guys) */
    172     KAFFINITY Mask = KeQueryActiveProcessors();
    173     return RTCpuSetFromU64(pSet, Mask);
    174 #else
     172    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     173
    175174    *pSet = g_rtMpNtCpuSet;
    176175    return pSet;
    177 #endif
    178176}
    179177
     
    236234    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
    237235    /*ASMAtomicIncU32(&pArgs->cHits); - not needed */
    238     pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
     236    pArgs->pfnWorker(RTMpCpuId(), pArgs->pvUser1, pArgs->pvUser2);
    239237    return 0;
    240238}
     
    250248{
    251249    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
    252     RTCPUID idCpu = KeGetCurrentProcessorNumber();
     250    RTCPUID idCpu = RTMpCpuId();
    253251    if (pArgs->idCpu != idCpu)
    254252    {
     
    269267{
    270268    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
    271     RTCPUID idCpu = KeGetCurrentProcessorNumber();
     269    RTCPUID idCpu = RTMpCpuId();
    272270    if (   pArgs->idCpu  == idCpu
    273271        || pArgs->idCpu2 == idCpu)
     
    289287{
    290288    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
    291     RTCPUID idCpu = KeGetCurrentProcessorNumber();
     289    RTCPUID idCpu = RTMpCpuId();
    292290    if (pArgs->idCpu == idCpu)
    293291    {
     
    348346
    349347    ASMAtomicIncU32(&pArgs->cHits);
    350     pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
     348    pArgs->pfnWorker(RTMpCpuId(), pArgs->pvUser1, pArgs->pvUser2);
    351349
    352350    /* Dereference the argument structure. */
     
    355353    if (cRefs == 0)
    356354        ExFreePool(pArgs);
     355}
     356
     357
     358/**
     359 * Wrapper around KeSetTargetProcessorDpcEx / KeSetTargetProcessorDpc.
     360 *
     361 * This is shared with the timer code.
     362 *
     363 * @returns IPRT status code (errors are asserted).
     364 * @param   pDpc                The DPC.
     365 * @param   idCpu               The ID of the new target CPU.
     366 */
     367DECLHIDDEN(int) rtMpNtSetTargetProcessorDpc(KDPC *pDpc, RTCPUID idCpu)
     368{
     369    if (g_pfnrtKeSetTargetProcessorDpcEx)
     370    {
     371        /* Convert to stupid process number (bet KeSetTargetProcessorDpcEx does
     372           the reverse conversion internally). */
     373        PROCESSOR_NUMBER ProcNum;
     374        NTSTATUS rcNt = g_pfnrtKeGetProcessorNumberFromIndex(idCpu, &ProcNum);
     375        AssertMsgReturn(NT_SUCCESS(rcNt),
     376                        ("KeGetProcessorNumberFromIndex(%u) -> %#x\n", idCpu, rcNt),
     377                        RTErrConvertFromNtStatus(rcNt));
     378
     379        rcNt = g_pfnrtKeSetTargetProcessorDpcEx(pDpc, &ProcNum);
     380        AssertMsgReturn(NT_SUCCESS(rcNt),
     381                        ("KeSetTargetProcessorDpcEx(,%u(%u/%u)) -> %#x\n", idCpu, ProcNum.Group, ProcNum.Number, rcNt),
     382                        RTErrConvertFromNtStatus(rcNt));
     383    }
     384    else
     385        KeSetTargetProcessorDpc(pDpc, (int)idCpu);
     386    return VINF_SUCCESS;
    357387}
    358388
     
    396426        return VERR_NOT_SUPPORTED;
    397427
    398     pArgs = (PRTMPARGS)ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_PROCESSORS*sizeof(KDPC) + sizeof(RTMPARGS), (ULONG)'RTMp');
     428    pArgs = (PRTMPARGS)ExAllocatePoolWithTag(NonPagedPool, g_cRtMpNtMaxCpus * sizeof(KDPC) + sizeof(RTMPARGS), (ULONG)'RTMp');
    399429    if (!pArgs)
    400430        return VERR_NO_MEMORY;
     
    410440    paExecCpuDpcs = (KDPC *)(pArgs + 1);
    411441
     442    int rc;
    412443    if (enmCpuid == RT_NT_CPUID_SPECIFIC)
    413444    {
    414445        KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs);
    415446        KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance);
    416         KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu);
     447        rc = rtMpNtSetTargetProcessorDpc(&paExecCpuDpcs[0], idCpu);
    417448        pArgs->idCpu = idCpu;
    418449    }
     
    421452        KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs);
    422453        KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance);
    423         KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu);
     454        rc = rtMpNtSetTargetProcessorDpc(&paExecCpuDpcs[0], idCpu);
    424455        pArgs->idCpu = idCpu;
    425456
    426457        KeInitializeDpc(&paExecCpuDpcs[1], rtmpNtDPCWrapper, pArgs);
    427458        KeSetImportanceDpc(&paExecCpuDpcs[1], HighImportance);
    428         KeSetTargetProcessorDpc(&paExecCpuDpcs[1], (int)idCpu2);
     459        if (RT_SUCCESS(rc))
     460            rc = rtMpNtSetTargetProcessorDpc(&paExecCpuDpcs[1], (int)idCpu2);
    429461        pArgs->idCpu2 = idCpu2;
    430462    }
    431463    else
    432464    {
    433         for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++)
     465        rc = VINF_SUCCESS;
     466        for (unsigned i = 0; i < g_cRtMpNtMaxCpus && RT_SUCCESS(rc); i++)
    434467        {
    435468            KeInitializeDpc(&paExecCpuDpcs[i], rtmpNtDPCWrapper, pArgs);
    436469            KeSetImportanceDpc(&paExecCpuDpcs[i], HighImportance);
    437             KeSetTargetProcessorDpc(&paExecCpuDpcs[i], i);
     470            rc = rtMpNtSetTargetProcessorDpc(&paExecCpuDpcs[i], i);
    438471        }
     472    }
     473    if (RT_FAILURE(rc))
     474    {
     475        ExFreePool(pArgs);
     476        return rc;
    439477    }
    440478
     
    469507    else
    470508    {
    471         unsigned iSelf = KeGetCurrentProcessorNumber();
    472 
    473         for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++)
     509        unsigned iSelf = RTMpCpuId();
     510
     511        for (unsigned i = 0; i < g_cRtMpNtMaxCpus; i++)
    474512        {
    475513            if (    (i != iSelf)
     
    505543
    506544    return VINF_SUCCESS;
    507 #endif /* */
     545#endif /* !IPRT_TARGET_NT4 */
    508546}
    509547
     
    611649    ASMAtomicWriteBool(&pArgs->fExecuting, true);
    612650
    613     pArgs->CallbackArgs.pfnWorker(KeGetCurrentProcessorNumber(), pArgs->CallbackArgs.pvUser1, pArgs->CallbackArgs.pvUser2);
     651    pArgs->CallbackArgs.pfnWorker(RTMpCpuId(), pArgs->CallbackArgs.pvUser1, pArgs->CallbackArgs.pvUser2);
    614652
    615653    ASMAtomicWriteBool(&pArgs->fDone, true);
     
    683721    KeInitializeDpc(&pArgs->Dpc, rtMpNtOnSpecificDpcWrapper, pArgs);
    684722    KeSetImportanceDpc(&pArgs->Dpc, HighImportance);
    685     KeSetTargetProcessorDpc(&pArgs->Dpc, (int)idCpu);
     723    rc = rtMpNtSetTargetProcessorDpc(&pArgs->Dpc, idCpu);
     724    if (RT_FAILURE(rc))
     725    {
     726        ExFreePool(pArgs);
     727        return rc;
     728    }
    686729
    687730    /*
     
    832875int rtMpPokeCpuUsingHalReqestIpiW7Plus(RTCPUID idCpu)
    833876{
    834     /*
    835      * I think we'll let idCpu be an NT processor number and not a HAL processor
    836      * index.  KeAddProcessorAffinityEx is for HAL and uses HAL processor
    837      * indexes as input from what I can tell.
    838      */
    839     PROCESSOR_NUMBER ProcNumber = { /*Group=*/ idCpu / 64, /*Number=*/ idCpu % 64, /* Reserved=*/ 0};
    840     KAFFINITY_EX     Target;
     877    /* idCpu is an HAL processor index, so we can use it directly. */
     878    KAFFINITY_EX Target;
    841879    g_pfnrtKeInitializeAffinityEx(&Target);
    842     g_pfnrtKeAddProcessorAffinityEx(&Target, g_pfnrtKeGetProcessorIndexFromNumber(&ProcNumber));
     880    g_pfnrtKeAddProcessorAffinityEx(&Target, idCpu);
    843881
    844882    g_pfnrtHalRequestIpiW7Plus(0, &Target);
     
    868906int rtMpPokeCpuUsingDpc(RTCPUID idCpu)
    869907{
     908    Assert(g_cRtMpNtMaxCpus > 0 && g_cRtMpNtMaxGroups > 0); /* init order */
     909
    870910    /*
    871911     * APC fallback.
    872912     */
    873     static KDPC s_aPokeDpcs[MAXIMUM_PROCESSORS] = {0};
     913    static KDPC s_aPokeDpcs[RTCPUSET_MAX_CPUS] = {0};
    874914    static bool s_fPokeDPCsInitialized = false;
    875915
    876916    if (!s_fPokeDPCsInitialized)
    877917    {
    878         for (unsigned i = 0; i < RT_ELEMENTS(s_aPokeDpcs); i++)
     918        for (unsigned i = 0; i < g_cRtMpNtMaxCpus; i++)
    879919        {
    880920            KeInitializeDpc(&s_aPokeDpcs[i], rtMpNtPokeCpuDummy, NULL);
    881921            KeSetImportanceDpc(&s_aPokeDpcs[i], HighImportance);
    882             KeSetTargetProcessorDpc(&s_aPokeDpcs[i], (int)i);
     922            int rc = rtMpNtSetTargetProcessorDpc(&s_aPokeDpcs[i], idCpu);
     923            if (RT_FAILURE(rc))
     924                return rc;
    883925        }
     926
    884927        s_fPokeDPCsInitialized = true;
    885928    }
     
    910953              ? VERR_CPU_NOT_FOUND
    911954              : VERR_CPU_OFFLINE;
    912     /* Calls rtMpSendIpiFallback, rtMpSendIpiWin7AndLater or rtMpSendIpiVista. */
     955    /* Calls rtMpPokeCpuUsingDpc, rtMpPokeCpuUsingHalReqestIpiW7Plus or rtMpPokeCpuUsingBroadcastIpi. */
    913956    return g_pfnrtMpPokeCpuWorker(idCpu);
    914957}
  • trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp

    r63063 r64234  
    511511    pTimer->u64NanoInterval = u64NanoInterval;
    512512    KeInitializeTimerEx(&pTimer->NtTimer, SynchronizationTimer);
     513    int rc = VINF_SUCCESS;
    513514    if (pTimer->fOmniTimer)
    514515    {
     
    519520         */
    520521        pTimer->idCpu = NIL_RTCPUID;
    521         for (unsigned iCpu = 0; iCpu < cSubTimers; iCpu++)
     522        for (unsigned iCpu = 0; iCpu < cSubTimers && RT_SUCCESS(rc); iCpu++)
    522523        {
    523524            pTimer->aSubTimers[iCpu].iTick = 0;
     
    533534                KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniSlaveCallback, &pTimer->aSubTimers[iCpu]);
    534535            KeSetImportanceDpc(&pTimer->aSubTimers[iCpu].NtDpc, HighImportance);
    535             KeSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, (int)RTMpCpuIdFromSetIndex(iCpu));
     536            rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, iCpu);
    536537        }
    537538        Assert(pTimer->idCpu != NIL_RTCPUID);
     
    549550        KeSetImportanceDpc(&pTimer->aSubTimers[0].NtDpc, HighImportance);
    550551        if (pTimer->fSpecificCpu)
    551             KeSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, (int)pTimer->idCpu);
    552     }
    553 
    554     *ppTimer = pTimer;
    555     return VINF_SUCCESS;
     552            rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, (int)pTimer->idCpu);
     553    }
     554    if (RT_SUCCESS(rc))
     555    {
     556        *ppTimer = pTimer;
     557        return VINF_SUCCESS;
     558    }
     559
     560    RTMemFree(pTimer);
     561    return rc;
    556562}
    557563
  • trunk/src/VBox/Runtime/r3/win/mp-win.cpp

    r64220 r64234  
    109109     *
    110110     * We ASSUME the the GroupInfo index is the same as the group number.
     111     *
    111112     * We ASSUME there are no inactive groups, because otherwise it will
    112113     * be difficult to tell how many possible CPUs we can have and do a
    113      * reasonable CPU ID/index partitioning.
     114     * reasonable CPU ID/index partitioning. [probably bad assumption]
     115     *
     116     * We ASSUME that the kernel processor indexes are assigned in group order,
     117     * which we match here with our own ID+index assignments.  This claim is
     118     * verified by initterm-r0drv-nt.cpp.
    114119     *
    115120     * Note! We will die if there are too many processors!
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette