VirtualBox

Changeset 45443 in vbox for trunk


Ignore:
Timestamp:
Apr 9, 2013 6:30:45 PM (12 years ago)
Author:
vboxsync
Message:

IPRT: Better way of finding QuantumEnd and DpcQueueDepth.

Location:
trunk/src/VBox/Runtime/r0drv/nt
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp

    r44528 r45443  
    55
    66/*
    7  * Copyright (C) 2006-2011 Oracle Corporation
     7 * Copyright (C) 2006-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3636#include "internal/initterm.h"
    3737#include "internal-r0drv-nt.h"
     38#include "symdb.h"
     39#include "symdbdata.h"
    3840
    3941
     
    4143*   Global Variables                                                           *
    4244*******************************************************************************/
    43 /** The Nt CPU set.
     45/** The NT CPU set.
    4446 * KeQueryActiveProcssors() cannot be called at all IRQLs and therefore we'll
    4547 * have to cache it. Fortunately, Nt doesn't really support taking CPUs offline
     
    6264/** KeIpiGenericCall - Windows Server 2003+ only */
    6365PFNRTKEIPIGENERICCALL       g_pfnrtKeIpiGenericCall;
     66/** RtlGetVersion, introduced in ??. */
     67PFNRTRTLGETVERSION          g_pfnrtRtlGetVersion;
    6468
    6569/** Offset of the _KPRCB::QuantumEnd field. 0 if not found. */
     
    7175
    7276
     77/**
     78 * Determines the NT kernel verison information.
     79 *
     80 * @param   pOsVerInfo          Where to return the version information.
     81 *
     82 * @remarks pOsVerInfo->fSmp is only definitive if @c true.
     83 * @remarks pOsVerInfo->uCsdNo is set to MY_NIL_CSD if it cannot be determined.
     84 */
     85static void rtR0NtGetOsVersionInfo(PRTNTSDBOSVER pOsVerInfo)
     86{
     87    ULONG       ulMajorVersion = 0;
     88    ULONG       ulMinorVersion = 0;
     89    ULONG       ulBuildNumber  = 0;
     90
     91    pOsVerInfo->fChecked    = PsGetVersion(&ulMajorVersion, &ulMinorVersion, &ulBuildNumber, NULL) == TRUE;
     92    pOsVerInfo->uMajorVer   = (uint8_t)ulMajorVersion;
     93    pOsVerInfo->uMinorVer   = (uint8_t)ulMinorVersion;
     94    pOsVerInfo->uBuildNo    = ulBuildNumber;
     95#define MY_NIL_CSD      0x3f
     96    pOsVerInfo->uCsdNo      = MY_NIL_CSD;
     97
     98    if (g_pfnrtRtlGetVersion)
     99    {
     100        RTL_OSVERSIONINFOEXW VerInfo;
     101        RT_ZERO(VerInfo);
     102        VerInfo.dwOSVersionInfoSize = sizeof(VerInfo);
     103
     104        NTSTATUS rcNt = g_pfnrtRtlGetVersion(&VerInfo);
     105        if (NT_SUCCESS(rcNt))
     106            pOsVerInfo->uCsdNo = VerInfo.wServicePackMajor;
     107    }
     108
     109    /* Note! We cannot quite say if something is MP or UNI. So, fSmp is
     110             redefined to indicate that it must be MP. */
     111    pOsVerInfo->fSmp        = RTMpGetCount() >  1
     112                           || ulMajorVersion >= 6; /* Vista and later has no UNI kernel AFAIK. */
     113}
     114
     115
     116/**
     117 * Tries a set against the current kernel.
     118 *
     119 * @retval @c true if it matched up, global variables are updated.
     120 * @retval @c false otherwise (no globals updated).
     121 * @param   pSet                The data set.
     122 * @param   pbPrcb              Pointer to the processor control block.
     123 * @param   pszVendor           Pointer to the processor vendor string.
     124 * @param   pOsVerInfo          The OS version info.
     125 */
     126static bool rtR0NtTryMatchSymSet(PCRTNTSDBSET pSet, uint8_t *pbPrcb, const char *pszVendor, PCRTNTSDBOSVER pOsVerInfo)
     127{
     128    /*
     129     * Don't bother trying stuff where the NT kernel version number differs, or
     130     * if the build type or SMPness doesn't match up.
     131     */
     132    if (   pSet->OsVerInfo.uMajorVer != pOsVerInfo->uMajorVer
     133        || pSet->OsVerInfo.uMinorVer != pOsVerInfo->uMinorVer
     134        || pSet->OsVerInfo.fChecked  != pOsVerInfo->fChecked
     135        || (!pSet->OsVerInfo.fSmp && pOsVerInfo->fSmp /*must-be-smp*/) )
     136    {
     137        //DbgPrint("IPRT: #%d Version/type mismatch.\n", pSet - &g_artNtSdbSets[0]);
     138        return false;
     139    }
     140
     141    /*
     142     * Do the CPU vendor test.
     143     */
     144    __try
     145    {
     146        if (memcmp(&pbPrcb[pSet->KPRCB.offVendorString], pszVendor,
     147                   RT_MIN(4 * 3, pSet->KPRCB.cbVendorString)) != 0)
     148        {
     149            //DbgPrint("IPRT: #%d Vendor string mismatch.\n");
     150            return false;
     151        }
     152    }
     153    __except(EXCEPTION_EXECUTE_HANDLER) /** @todo this handler doesn't seem to work... Because of Irql? */
     154    {
     155        //DbgPrint("IPRT: Exception\n");
     156        return false;
     157    }
     158
     159    /*
     160     * Got a match, update the global variables and report succcess.
     161     */
     162    g_offrtNtPbQuantumEnd    = pSet->KPRCB.offQuantumEnd;
     163    g_cbrtNtPbQuantumEnd     = pSet->KPRCB.cbQuantumEnd;
     164    g_offrtNtPbDpcQueueDepth = pSet->KPRCB.offDpcQueueDepth;
     165
     166#if 0
     167    DbgPrint("IPRT: Using data set #%u for %u.%usp%u build %u %s %s.\n",
     168             pSet - &g_artNtSdbSets[0],
     169             pSet->OsVerInfo.uMajorVer,
     170             pSet->OsVerInfo.uMinorVer,
     171             pSet->OsVerInfo.uCsdNo,
     172             pSet->OsVerInfo.uBuildNo,
     173             pSet->OsVerInfo.fSmp ? "smp" : "uni",
     174             pSet->OsVerInfo.fChecked ? "checked" : "free");
     175#endif
     176    return true;
     177}
     178
    73179
    74180DECLHIDDEN(int) rtR0InitNative(void)
     
    92198    g_pfnrtNtHalSendSoftwareInterrupt = NULL;
    93199    g_pfnrtKeIpiGenericCall = NULL;
     200    g_pfnrtRtlGetVersion = NULL;
    94201#else
    95202    /*
     
    111218    RtlInitUnicodeString(&RoutineName, L"KeIpiGenericCall");
    112219    g_pfnrtKeIpiGenericCall = (PFNRTKEIPIGENERICCALL)MmGetSystemRoutineAddress(&RoutineName);
    113 #endif
    114 
    115     /*
    116      * Get some info that might come in handy below.
    117      */
    118     ULONG MajorVersion = 0;
    119     ULONG MinorVersion = 0;
    120     ULONG BuildNumber  = 0;
    121     BOOLEAN fChecked = PsGetVersion(&MajorVersion, &MinorVersion, &BuildNumber, NULL);
    122 
    123     g_pfnrtSendIpi = rtMpSendIpiDummy;
    124 #ifndef IPRT_TARGET_NT4
    125     if (    g_pfnrtNtHalRequestIpi
    126         &&  MajorVersion == 6
    127         &&  MinorVersion == 0)
    128     {
    129         /* Vista or Windows Server 2008 */
    130         g_pfnrtSendIpi = rtMpSendIpiVista;
    131     }
    132     else
    133     if (    g_pfnrtNtHalSendSoftwareInterrupt
    134         &&  MajorVersion == 6
    135         &&  MinorVersion == 1)
    136     {
    137         /* Windows 7 or Windows Server 2008 R2 */
    138         g_pfnrtSendIpi = rtMpSendIpiWin7;
    139     }
    140     /* Windows XP should send always send an IPI -> VERIFY */
    141 #endif
    142     KIRQL OldIrql;
    143     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */
    144 
    145     union
    146     {
    147         uint32_t auRegs[4];
    148         char szVendor[4*3+1];
    149     } u;
    150     ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]);
    151     u.szVendor[4*3] = '\0';
     220
     221    RtlInitUnicodeString(&RoutineName, L"RtlGetVersion");
     222    g_pfnrtRtlGetVersion = (PFNRTRTLGETVERSION)MmGetSystemRoutineAddress(&RoutineName);
     223#endif
    152224
    153225    /*
     
    162234     *      dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString"
    163235     */
    164     /** @todo array w/ data + script for extracting a row. (save space + readability; table will be short.) */
     236
     237    RTNTSDBOSVER OsVerInfo;
     238    rtR0NtGetOsVersionInfo(&OsVerInfo);
     239
     240    /*
     241     * Gather consistent CPU vendor string and PRCB pointers.
     242     */
     243    KIRQL OldIrql;
     244    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */
     245
     246    union
     247    {
     248        uint32_t auRegs[4];
     249        char szVendor[4*3+1];
     250    } u;
     251    ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]);
     252    u.szVendor[4*3] = '\0';
     253
     254    uint8_t *pbPrcb;
    165255    __try
    166256    {
    167257#if defined(RT_ARCH_X86)
    168258        PKPCR    pPcr   = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr));
    169         uint8_t *pbPrcb = (uint8_t *)pPcr->Prcb;
    170 
    171         if (    BuildNumber == 2600                             /* XP SP2 */
    172             &&  !memcmp(&pbPrcb[0x900], &u.szVendor[0], 4*3))
    173         {
    174             g_offrtNtPbQuantumEnd    = 0x88c;
    175             g_cbrtNtPbQuantumEnd     = 4;
    176             g_offrtNtPbDpcQueueDepth = 0x870;
    177         }
    178         /* WindowsVista.6002.090410-1830.x86fre.Symbols.exe
    179            WindowsVista.6002.090410-1830.x86chk.Symbols.exe
    180            WindowsVista.6002.090130-1715.x86fre.Symbols.exe
    181            WindowsVista.6002.090130-1715.x86chk.Symbols.exe */
    182         else if (   BuildNumber == 6002
    183                  && !memcmp(&pbPrcb[0x1c2c], &u.szVendor[0], 4*3))
    184         {
    185             g_offrtNtPbQuantumEnd    = 0x1a41;
    186             g_cbrtNtPbQuantumEnd     = 1;
    187             g_offrtNtPbDpcQueueDepth = 0x19e0 + 0xc;
    188         }
    189         else if (   BuildNumber == 3790                         /* Server 2003 SP2 */
    190                  && !memcmp(&pbPrcb[0xb60], &u.szVendor[0], 4*3))
    191         {
    192             g_offrtNtPbQuantumEnd    = 0x981;
    193             g_cbrtNtPbQuantumEnd     = 1;
    194             g_offrtNtPbDpcQueueDepth = 0x920 + 0xc;
    195         }
    196 
    197         /** @todo more */
    198         //pbQuantumEnd = (uint8_t volatile *)pPcr->Prcb + 0x1a41;
    199 
     259        pbPrcb = (uint8_t *)pPcr->Prcb;
    200260#elif defined(RT_ARCH_AMD64)
    201261        PKPCR    pPcr   = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self));
    202         uint8_t *pbPrcb = (uint8_t *)pPcr->CurrentPrcb;
    203 
    204         if (    BuildNumber == 3790                             /* XP64 / W2K3-AMD64 SP1 */
    205             &&  !memcmp(&pbPrcb[0x22b4], &u.szVendor[0], 4*3))
    206         {
    207             g_offrtNtPbQuantumEnd    = 0x1f75;
    208             g_cbrtNtPbQuantumEnd     = 1;
    209             g_offrtNtPbDpcQueueDepth = 0x1f00 + 0x18;
    210         }
    211         else if (   BuildNumber == 6000                         /* Vista/AMD64 */
    212                  && !memcmp(&pbPrcb[0x38bc], &u.szVendor[0], 4*3))
    213         {
    214             g_offrtNtPbQuantumEnd    = 0x3375;
    215             g_cbrtNtPbQuantumEnd     = 1;
    216             g_offrtNtPbDpcQueueDepth = 0x3300 + 0x18;
    217         }
    218         /* WindowsVista.6002.090410-1830.amd64fre.Symbols
    219            WindowsVista.6002.090130-1715.amd64fre.Symbols
    220            WindowsVista.6002.090410-1830.amd64chk.Symbols */
    221         else if (   BuildNumber == 6002
    222                  && !memcmp(&pbPrcb[0x399c], &u.szVendor[0], 4*3))
    223         {
    224             g_offrtNtPbQuantumEnd    = 0x3475;
    225             g_cbrtNtPbQuantumEnd     = 1;
    226             g_offrtNtPbDpcQueueDepth = 0x3400 + 0x18;
    227         }
    228         /* Windows7.7600.16539.amd64fre.win7_gdr.100226-1909 */
    229         else if (    BuildNumber == 7600
    230                  && !memcmp(&pbPrcb[0x4bb8], &u.szVendor[0], 4*3))
    231         {
    232             g_offrtNtPbQuantumEnd    = 0x21d9;
    233             g_cbrtNtPbQuantumEnd     = 1;
    234             g_offrtNtPbDpcQueueDepth = 0x2180 + 0x18;
    235         }
    236 
     262        pbPrcb = (uint8_t *)pPcr->CurrentPrcb;
    237263#else
    238264# error "port me"
     265        pbPrcb = NULL;
    239266#endif
    240267    }
    241268    __except(EXCEPTION_EXECUTE_HANDLER) /** @todo this handler doesn't seem to work... Because of Irql? */
    242269    {
    243         g_offrtNtPbQuantumEnd    = 0;
    244         g_cbrtNtPbQuantumEnd     = 0;
    245         g_offrtNtPbDpcQueueDepth = 0;
    246     }
    247 
    248     KeLowerIrql(OldIrql);
    249 
    250 #ifndef IN_GUEST /** @todo fix above for all Nt versions. */
     270        pbPrcb = NULL;
     271    }
     272
     273    KeLowerIrql(OldIrql); /* Lowering the IRQL early in the hope that we may catch exceptions below. */
     274
     275    /*
     276     * Search the database
     277     */
     278    if (pbPrcb)
     279    {
     280        /* Find the best matching kernel version based on build number. */
     281        uint32_t iBest      = UINT32_MAX;
     282        int32_t  iBestDelta = INT32_MAX;
     283        for (uint32_t i = 0; i < RT_ELEMENTS(g_artNtSdbSets); i++)
     284        {
     285            if (g_artNtSdbSets[i].OsVerInfo.fChecked != OsVerInfo.fChecked)
     286                continue;
     287            if (OsVerInfo.fSmp /*must-be-smp*/ && !g_artNtSdbSets[i].OsVerInfo.fSmp)
     288                continue;
     289
     290            int32_t iDelta = RT_ABS((int32_t)OsVerInfo.uBuildNo - (int32_t)g_artNtSdbSets[i].OsVerInfo.uBuildNo);
     291            if (   iDelta == 0
     292                && (g_artNtSdbSets[i].OsVerInfo.uCsdNo == OsVerInfo.uCsdNo || OsVerInfo.uCsdNo == MY_NIL_CSD))
     293            {
     294                /* prefect */
     295                iBestDelta = iDelta;
     296                iBest      = i;
     297                break;
     298            }
     299            if (   iDelta < iBestDelta
     300                || iBest == UINT32_MAX
     301                || (   iDelta == iBestDelta
     302                    && OsVerInfo.uCsdNo != MY_NIL_CSD
     303                    &&   RT_ABS(g_artNtSdbSets[i    ].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo)
     304                       < RT_ABS(g_artNtSdbSets[iBest].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo)
     305                   )
     306                )
     307            {
     308                iBestDelta = iDelta;
     309                iBest      = i;
     310            }
     311        }
     312        iBest = RT_ELEMENTS(g_artNtSdbSets)-1;
     313        if (iBest < RT_ELEMENTS(g_artNtSdbSets))
     314        {
     315            /* Try all sets: iBest -> End; iBest -> Start. */
     316            bool    fDone = false;
     317            int32_t i     = iBest;
     318            while (   i < RT_ELEMENTS(g_artNtSdbSets)
     319                   && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo)))
     320                i++;
     321            if (!fDone)
     322            {
     323                i = (int32_t)iBest - 1;
     324                while (   i >= 0
     325                       && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo)))
     326                    i--;
     327            }
     328        }
     329        else
     330            DbgPrint("IPRT: Failed to locate data set.\n");
     331    }
     332    else
     333        DbgPrint("IPRT: Failed to get PCBR pointer.\n");
     334
     335#ifndef IN_GUEST
    251336    if (!g_offrtNtPbQuantumEnd && !g_offrtNtPbDpcQueueDepth)
    252337        DbgPrint("IPRT: Neither _KPRCB::QuantumEnd nor _KPRCB::DpcQueueDepth was not found! Kernel %u.%u %u %s\n",
    253                  MajorVersion, MinorVersion, BuildNumber, fChecked ? "checked" : "free");
     338                 OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free");
    254339# ifdef DEBUG
    255340    else
    256         DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %ul.%ul %ul %s\n",
     341        DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %u.%u %u %s\n",
    257342                 g_offrtNtPbQuantumEnd, g_cbrtNtPbQuantumEnd, g_offrtNtPbDpcQueueDepth,
    258                  MajorVersion, MinorVersion, BuildNumber, fChecked ? "checked" : "free");
     343                 OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free");
    259344# endif
     345#endif
     346
     347    /*
     348     * Special IPI fun.
     349     */
     350    g_pfnrtSendIpi = rtMpSendIpiDummy;
     351#ifndef IPRT_TARGET_NT4
     352    if (    g_pfnrtNtHalRequestIpi
     353        &&  OsVerInfo.uMajorVer == 6
     354        &&  OsVerInfo.uMinorVer == 0)
     355    {
     356        /* Vista or Windows Server 2008 */
     357        g_pfnrtSendIpi = rtMpSendIpiVista;
     358    }
     359    else if (   g_pfnrtNtHalSendSoftwareInterrupt
     360             && OsVerInfo.uMajorVer == 6
     361             && OsVerInfo.uMinorVer == 1)
     362    {
     363        /* Windows 7 or Windows Server 2008 R2 */
     364        g_pfnrtSendIpi = rtMpSendIpiWin7;
     365    }
     366    /* Windows XP should send always send an IPI -> VERIFY */
    260367#endif
    261368
  • trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h

    r44529 r45443  
    4141typedef int (__stdcall *PFNRTSENDIPI)(RTCPUID idCpu);
    4242typedef ULONG_PTR (__stdcall *PFNRTKEIPIGENERICCALL)(PKIPI_BROADCAST_WORKER BroadcastFunction, ULONG_PTR  Context);
     43typedef ULONG (__stdcall *PFNRTRTLGETVERSION)(PRTL_OSVERSIONINFOEXW pVerInfo);
    4344
    4445/*******************************************************************************
     
    5253extern PFNRTSENDIPI                 g_pfnrtSendIpi;
    5354extern PFNRTKEIPIGENERICCALL        g_pfnrtKeIpiGenericCall;
     55extern PFNRTRTLGETVERSION             g_pfnrtRtlGetVersion;
    5456extern uint32_t                     g_offrtNtPbQuantumEnd;
    5557extern uint32_t                     g_cbrtNtPbQuantumEnd;
  • trunk/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp

    r45440 r45443  
    260260    {
    261261        const char *pszStructName = figureCStructName(&g_aStructs[i]);
    262         RTStrmPrintf(pOut, "    RTNTSDBTYPE_%-20s %s\n", pszStructName, pszStructName);
     262        RTStrmPrintf(pOut, "    RTNTSDBTYPE_%-20s %s;\n", pszStructName, pszStructName);
    263263    }
    264264    RTStrmPrintf(pOut,
     
    273273                 "\n"
    274274                 "#ifndef RTNTSDB_NO_DATA\n"
    275                  "const RTNTSDBSET g_rtNtSdbSets[] = \n"
     275                 "const RTNTSDBSET g_artNtSdbSets[] = \n"
    276276                 "{\n");
    277277    PMYSET pSet;
     
    299299                     pSet->OsVerInfo.uCsdNo,
    300300                     pSet->OsVerInfo.uBuildNo);
    301         for (uint32_t i = 0; i < RT_ELEMENTS(g_aStructs); i++)
    302         {
    303             const char *pszStructName = figureCStructName(&g_aStructs[i]);
     301        for (uint32_t i = 0; i < RT_ELEMENTS(pSet->aStructs); i++)
     302        {
     303            const char *pszStructName = figureCStructName(&pSet->aStructs[i]);
    304304            RTStrmPrintf(pOut,
    305305                         "        /* .%s = */\n"
    306306                         "        {\n", pszStructName);
    307             PMYMEMBER paMembers = g_aStructs[i].paMembers;
    308             for (uint32_t j = 0; j < g_aStructs->cMembers; j++)
     307            PMYMEMBER paMembers = pSet->aStructs[i].paMembers;
     308            for (uint32_t j = 0; j < pSet->aStructs[i].cMembers; j++)
    309309            {
    310310                const char *pszMemName = figureCMemberName(&paMembers[j]);
     
    329329                 "\n");
    330330
    331     RTStrmPrintf(pOut, "\n#endif\n");
     331    RTStrmPrintf(pOut, "\n#endif\n\n");
    332332}
    333333
     
    387387            if (iDiff > 0 || pInsertBefore->enmArch > pSet->enmArch)
    388388            {
    389                 RTListPrepend(&pInsertBefore->ListEntry, &pSet->ListEntry);
     389                RTListNodeInsertBefore(&pInsertBefore->ListEntry, &pSet->ListEntry);
    390390                return RTEXITCODE_SUCCESS;
    391391            }
Note: See TracChangeset for help on using the changeset viewer.

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