VirtualBox

Ignore:
Timestamp:
Feb 27, 2018 1:17:36 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
121023
Message:

SUPDrv,VMM/NEM/win: Abstracted kernel I/O control work in SUPDrv, currently only implemented & needed on windows. Made first I/O control call to VID from ring-0. bugref:9044

Location:
trunk/src/VBox/HostDrivers/Support
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp

    r71075 r71136  
    231231    { "SUPR0TracerUmodProbeFire",               (void *)(uintptr_t)SUPR0TracerUmodProbeFire },
    232232    { "SUPR0UnlockMem",                         (void *)(uintptr_t)SUPR0UnlockMem },
     233#ifdef RT_OS_WINDOWS
     234    { "SUPR0IoCtlSetupForHandle",               (void *)(uintptr_t)SUPR0IoCtlSetupForHandle },  /* only-windows */
     235    { "SUPR0IoCtlPerform",                      (void *)(uintptr_t)SUPR0IoCtlPerform },         /* only-windows */
     236    { "SUPR0IoCtlCleanup",                      (void *)(uintptr_t)SUPR0IoCtlCleanup },         /* only-windows */
     237#endif
    233238    { "SUPSemEventClose",                       (void *)(uintptr_t)SUPSemEventClose },
    234239    { "SUPSemEventCreate",                      (void *)(uintptr_t)SUPSemEventCreate },
  • trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h

    r71075 r71136  
    214214 * @remarks 0x002a0000 is used by 5.1. The next version number must be 0x002b0000.
    215215 */
    216 #define SUPDRV_IOC_VERSION                              0x00290002
     216#define SUPDRV_IOC_VERSION                              0x00290003
    217217
    218218/** SUP_IOCTL_COOKIE. */
  • trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h

    r70917 r71136  
    455455    uint32_t volatile               cUsage;
    456456} SUPDRVUSAGE, *PSUPDRVUSAGE;
     457
     458
     459/**
     460 * I/O control context.
     461 */
     462typedef struct SUPR0IOCTLCTX
     463{
     464    /** Magic value (SUPR0IOCTLCTX_MAGIC). */
     465    uint32_t                u32Magic;
     466    /** Reference counter. */
     467    uint32_t volatile       cRefs;
     468#ifdef RT_OS_WINDOWS
     469# ifndef SUPDRV_AGNOSTIC
     470    /** The file object, referenced. */
     471    PFILE_OBJECT            pFileObject;
     472    /** The device object, not referenced. */
     473    PDEVICE_OBJECT          pDeviceObject;
     474    /** Pointer to fast I/O routine if available. */
     475    FAST_IO_DEVICE_CONTROL *pfnFastIoDeviceControl;
     476# else
     477    void                   *apvPadding[3];
     478# endif
     479#endif
     480} SUPR0IOCTLCTX;
     481/** Magic value for SUPR0IOCTLCTX (Ahmad Jamal). */
     482#define SUPR0IOCTLCTX_MAGIC     UINT32_C(0x19300702)
    457483
    458484
  • trunk/src/VBox/HostDrivers/Support/SUPLib.cpp

    r71075 r71136  
    277277        CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
    278278        const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00290000
    279                                    ? 0x00290002
     279                                   ? 0x00290003
    280280                                   : SUPDRV_IOC_VERSION & 0xffff0000;
    281281        CookieReq.u.In.u32MinVersion = uMinVersion;
  • trunk/src/VBox/HostDrivers/Support/SUPLibLdr.cpp

    r69500 r71136  
    167167     * Only SUPR0 and VMMR0.r0
    168168     */
    169     if (    pszModule
    170         &&  *pszModule
    171         &&  strcmp(pszModule, "VBoxDrv.sys")
    172         &&  strcmp(pszModule, "VMMR0.r0"))
    173     {
     169    if (   pszModule
     170        && *pszModule
     171        && strcmp(pszModule, "VBoxDrv.sys")
     172        && strcmp(pszModule, "VMMR0.r0"))
     173    {
     174#if defined(RT_OS_WINDOWS) && 0 /* Useful for VMMR0 hacking, not for production use.  See also SUPDrv-win.cpp */
     175        if (strcmp(pszModule, "ntoskrnl.exe") == 0)
     176        {
     177            *pValue = 42; /* Non-zero so ring-0 can find the end of the IAT and exclude it when comparing. */
     178            return VINF_SUCCESS;
     179        }
     180#endif
    174181        AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitive)\n", pArgs->pszModule, pszModule));
    175182        return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND,
  • trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp

    r70917 r71136  
    21312131}
    21322132
     2133/** Image compare exclusion regions. */
     2134typedef struct SUPDRVNTEXCLREGIONS
     2135{
     2136    /** Number of regions.   */
     2137    uint32_t        cRegions;
     2138    /** The regions. */
     2139    struct SUPDRVNTEXCLREGION
     2140    {
     2141        uint32_t    uRva;
     2142        uint32_t    cb;
     2143    }               aRegions[16];
     2144} SUPDRVNTEXCLREGIONS;
     2145
     2146/**
     2147 * Adds an exclusion region to the collection.
     2148 */
     2149static bool supdrvNtAddExclRegion(SUPDRVNTEXCLREGIONS *pRegions, uint32_t uRvaRegion, uint32_t cbRegion)
     2150{
     2151    uint32_t const cRegions = pRegions->cRegions;
     2152    AssertReturn(cRegions + 1 <= RT_ELEMENTS(pRegions->aRegions), false);
     2153    uint32_t i = 0;
     2154    for (; i < cRegions; i++)
     2155        if (uRvaRegion < pRegions->aRegions[i].uRva)
     2156            break;
     2157    if (i != cRegions)
     2158        memmove(&pRegions->aRegions[i + 1], &pRegions->aRegions[i], (cRegions - i) * sizeof(pRegions->aRegions[0]));
     2159    pRegions->aRegions[i].uRva = uRvaRegion;
     2160    pRegions->aRegions[i].cb   = cbRegion;
     2161    pRegions->cRegions++;
     2162    return true;
     2163}
     2164
    21332165
    21342166int  VBOXCALL   supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
     
    21842216            )
    21852217        {
    2186             struct MyRegion
    2187             {
    2188                 uint32_t uRva;
    2189                 uint32_t cb;
    2190             }           aExcludeRgns[16];
    2191             unsigned    cExcludeRgns = 0;
     2218            SUPDRVNTEXCLREGIONS ExcludeRegions;
     2219            ExcludeRegions.cRegions = 0;
    21922220
    21932221            /* ImageBase: */
     
    21952223                && (   pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
    21962224                    || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) )
    2197             {
    2198                 aExcludeRgns[cExcludeRgns].uRva = offImageBase;
    2199                 aExcludeRgns[cExcludeRgns].cb   = cbImageBase;
    2200                 cExcludeRgns++;
    2201             }
     2225                supdrvNtAddExclRegion(&ExcludeRegions, offImageBase, cbImageBase);
    22022226
    22032227            /* Imports: */
     
    22082232            IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
    22092233            while (   cImpsLeft-- > 0
    2210                    && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
     2234                   && ExcludeRegions.cRegions < RT_ELEMENTS(ExcludeRegions.aRegions))
    22112235            {
    22122236                uint32_t uRvaThunk = pImp->OriginalFirstThunk;
    2213                 if (    uRvaThunk >  sizeof(IMAGE_NT_HEADERS)
    2214                     &&  uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
    2215                     &&  uRvaThunk != pImp->FirstThunk)
     2237                if (   uRvaThunk >  sizeof(IMAGE_NT_HEADERS)
     2238                    && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
     2239                    && uRvaThunk != pImp->FirstThunk)
    22162240                {
    22172241                    /* Find the size of the thunk table. */
     
    22212245                    while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
    22222246                        cThunks++;
    2223 
    2224                     /* Ordered table insert. */
    2225                     unsigned i = 0;
    2226                     for (; i < cExcludeRgns; i++)
    2227                         if (uRvaThunk < aExcludeRgns[i].uRva)
    2228                             break;
    2229                     if (i != cExcludeRgns)
    2230                         memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0]));
    2231                     aExcludeRgns[i].uRva = uRvaThunk;
    2232                     aExcludeRgns[i].cb   = cThunks * sizeof(IMAGE_THUNK_DATA);
    2233                     cExcludeRgns++;
     2247                    supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
    22342248                }
     2249
     2250#if 0 /* Useful for VMMR0 hacking, not for production use.  See also SUPDrvLdr.cpp. */
     2251                /* Exclude the other thunk table if ntoskrnl.exe. */
     2252                uint32_t uRvaName = pImp->Name;
     2253                if (   uRvaName > sizeof(IMAGE_NT_HEADERS)
     2254                    && uRvaName < pImage->cbImageBits - sizeof("ntoskrnl.exe")
     2255                    && memcmp(&pbImageBits[uRvaName], RT_STR_TUPLE("ntoskrnl.exe")) == 0)
     2256                {
     2257                    uRvaThunk = pImp->FirstThunk;
     2258                    if (   uRvaThunk >  sizeof(IMAGE_NT_HEADERS)
     2259                        && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA))
     2260                    {
     2261                        /* Find the size of the thunk table. */
     2262                        IMAGE_THUNK_DATA const *paThunk    = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
     2263                        uint32_t                cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
     2264                        uint32_t                cThunks    = 0;
     2265                        while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
     2266                            cThunks++;
     2267                        supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
     2268                    }
     2269                }
     2270#endif
    22352271
    22362272                /* advance */
     
    22432279            int         iDiff    = 0;
    22442280            uint32_t    uRvaNext = 0;
    2245             for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)
    2246             {
    2247                 if (uRvaNext < aExcludeRgns[i].uRva)
    2248                     iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext, pReq);
    2249                 uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;
     2281            for (unsigned i = 0; !iDiff && i < ExcludeRegions.cRegions; i++)
     2282            {
     2283                if (uRvaNext < ExcludeRegions.aRegions[i].uRva)
     2284                    iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, ExcludeRegions.aRegions[i].uRva - uRvaNext, pReq);
     2285                uRvaNext = ExcludeRegions.aRegions[i].uRva + ExcludeRegions.aRegions[i].cb;
    22502286            }
    22512287            if (!iDiff && uRvaNext < pImage->cbImageBits)
     
    25582594{
    25592595    return 0;
     2596}
     2597
     2598
     2599SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx)
     2600{
     2601    /*
     2602     * Validate input.
     2603     */
     2604    AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
     2605    *ppCtx = NULL;
     2606    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
     2607    AssertReturn(!fFlags, VERR_INVALID_FLAGS);
     2608
     2609    /*
     2610     * Turn the partition handle into a file object and related device object
     2611     * so that we can issue direct I/O control calls to the pair later.
     2612     */
     2613    PFILE_OBJECT pFileObject = NULL;
     2614    OBJECT_HANDLE_INFORMATION HandleInfo = { 0, 0 };
     2615    NTSTATUS rcNt = ObReferenceObjectByHandle((HANDLE)hHandle, /*FILE_WRITE_DATA*/0, *IoFileObjectType,
     2616                                              UserMode, (void **)&pFileObject, &HandleInfo);
     2617    if (!NT_SUCCESS(rcNt))
     2618        return RTErrConvertFromNtStatus(rcNt);
     2619    AssertPtrReturn(pFileObject, VERR_INTERNAL_ERROR_3);
     2620
     2621    PDEVICE_OBJECT pDevObject = IoGetRelatedDeviceObject(pFileObject);
     2622    AssertMsgReturnStmt(RT_VALID_PTR(pDevObject), ("pDevObject=%p\n", pDevObject),
     2623                        ObDereferenceObject(pFileObject), VERR_INTERNAL_ERROR_2);
     2624
     2625    /*
     2626     * Allocate a context structure and fill it in.
     2627     */
     2628    PSUPR0IOCTLCTX pCtx = (PSUPR0IOCTLCTX)RTMemAllocZ(sizeof(*pCtx));
     2629    if (pCtx)
     2630    {
     2631        pCtx->u32Magic      = SUPR0IOCTLCTX_MAGIC;
     2632        pCtx->cRefs         = 1;
     2633        pCtx->pFileObject   = pFileObject;
     2634        pCtx->pDeviceObject = pDevObject;
     2635
     2636        PDRIVER_OBJECT pDrvObject = pDevObject->DriverObject;
     2637        if (   RT_VALID_PTR(pDrvObject->FastIoDispatch)
     2638            && RT_VALID_PTR(pDrvObject->FastIoDispatch->FastIoDeviceControl))
     2639            pCtx->pfnFastIoDeviceControl = pDrvObject->FastIoDispatch->FastIoDeviceControl;
     2640        else
     2641            pCtx->pfnFastIoDeviceControl = NULL;
     2642        *ppCtx = pCtx;
     2643        return VINF_SUCCESS;
     2644    }
     2645
     2646    ObDereferenceObject(pFileObject);
     2647    return VERR_NO_MEMORY;
     2648}
     2649
     2650
     2651/**
     2652 * I/O control destructor for NT.
     2653 *
     2654 * @param   pCtx    The context to destroy.
     2655 */
     2656static void supdrvNtIoCtlContextDestroy(PSUPR0IOCTLCTX pCtx)
     2657{
     2658    PFILE_OBJECT pFileObject = pCtx->pFileObject;
     2659    pCtx->pfnFastIoDeviceControl = NULL;
     2660    pCtx->pFileObject            = NULL;
     2661    pCtx->pDeviceObject          = NULL;
     2662    ASMAtomicWriteU32(&pCtx->u32Magic, ~SUPR0IOCTLCTX_MAGIC);
     2663
     2664    if (RT_VALID_PTR(pFileObject))
     2665        ObDereferenceObject(pFileObject);
     2666    RTMemFree(pCtx);
     2667}
     2668
     2669
     2670SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx)
     2671{
     2672    if (pCtx != NULL)
     2673    {
     2674        AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     2675        AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
     2676
     2677        uint32_t cRefs = ASMAtomicDecU32(&pCtx->cRefs);
     2678        Assert(cRefs < _4K);
     2679        if (cRefs == 0)
     2680            supdrvNtIoCtlContextDestroy(pCtx);
     2681    }
     2682    return VINF_SUCCESS;
     2683}
     2684
     2685
     2686SUPR0DECL(int)  SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction,
     2687                                  void *pvInput, RTR3PTR pvInputUser, size_t cbInput,
     2688                                  void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput,
     2689                                  int32_t *piNativeRc)
     2690{
     2691    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     2692    AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
     2693
     2694    /* Reference the context. */
     2695    uint32_t cRefs = ASMAtomicIncU32(&pCtx->cRefs);
     2696    Assert(cRefs > 1 && cRefs < _4K);
     2697
     2698    /*
     2699     * Try fast I/O control path first.
     2700     */
     2701    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     2702    if (pCtx->pfnFastIoDeviceControl)
     2703    {
     2704        /* Must pass user addresses here as that's what's being expected. */
     2705        BOOLEAN fHandled = pCtx->pfnFastIoDeviceControl(pCtx->pFileObject,
     2706                                                        TRUE /*Wait*/,
     2707                                                        (void *)pvInputUser,  (ULONG)cbInput,
     2708                                                        (void *)pvOutputUser, (ULONG)cbOutput,
     2709                                                        uFunction,
     2710                                                        &Ios,
     2711                                                        pCtx->pDeviceObject);
     2712        if (fHandled)
     2713        {
     2714            /* Relase the context. */
     2715            cRefs = ASMAtomicDecU32(&pCtx->cRefs);
     2716            Assert(cRefs < _4K);
     2717            if (cRefs == 0)
     2718                supdrvNtIoCtlContextDestroy(pCtx);
     2719
     2720            /* Set/convert status and return. */
     2721            if (piNativeRc)
     2722            {
     2723                *piNativeRc = Ios.Status;
     2724                return VINF_SUCCESS;
     2725            }
     2726            if (NT_SUCCESS(Ios.Status))
     2727                return VINF_SUCCESS;
     2728            return RTErrConvertFromNtStatus(Ios.Status);
     2729        }
     2730
     2731        /*
     2732         * Fall back on IRP if not handled.
     2733         *
     2734         * Note! Perhaps we should rather fail, because VID.SYS will crash getting
     2735         *       the partition ID with the code below.  It tries to zero the output
     2736         *       buffer as if it were as system buffer...
     2737         */
     2738        RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
     2739    }
     2740
     2741    /*
     2742     * For directly accessed buffers we must supply user mode addresses or
     2743     * we'll fail ProbeForWrite validation.
     2744     */
     2745    switch (uFunction & 3)
     2746    {
     2747        case METHOD_BUFFERED:
     2748            /* For buffered accesses, we can supply kernel buffers. */
     2749            break;
     2750
     2751        case METHOD_IN_DIRECT:
     2752            pvInput  = (void *)pvInputUser;
     2753            break;
     2754
     2755        case METHOD_NEITHER:
     2756            pvInput  = (void *)pvInputUser;
     2757            RT_FALL_THRU();
     2758
     2759        case METHOD_OUT_DIRECT:
     2760            pvOutput = (void *)pvOutputUser;
     2761            break;
     2762    }
     2763
     2764    /*
     2765     * Build the request.
     2766     */
     2767    int rc;
     2768    KEVENT Event;
     2769    KeInitializeEvent(&Event, NotificationEvent, FALSE);
     2770
     2771    PIRP pIrp = IoBuildDeviceIoControlRequest(uFunction, pCtx->pDeviceObject,
     2772                                              pvInput, (ULONG)cbInput, pvOutput, (ULONG)cbOutput,
     2773                                              FALSE /* InternalDeviceControl */, &Event, &Ios);
     2774    if (pIrp)
     2775    {
     2776        IoGetNextIrpStackLocation(pIrp)->FileObject = pCtx->pFileObject;
     2777
     2778        /*
     2779         * Make the call.
     2780         */
     2781        NTSTATUS rcNt = IoCallDriver(pCtx->pDeviceObject, pIrp);
     2782        if (rcNt == STATUS_PENDING)
     2783        {
     2784            rcNt = KeWaitForSingleObject(&Event,            /* Object */
     2785                                         Executive,         /* WaitReason */
     2786                                         KernelMode,        /* WaitMode */
     2787                                         FALSE,             /* Alertable */
     2788                                         NULL);             /* TimeOut */
     2789            AssertMsg(rcNt == STATUS_SUCCESS, ("rcNt=%#x\n", rcNt));
     2790            rcNt = Ios.Status;
     2791        }
     2792        else if (NT_SUCCESS(rcNt) && Ios.Status != STATUS_SUCCESS)
     2793            rcNt = Ios.Status;
     2794
     2795        /* Set/convert return code. */
     2796        if (piNativeRc)
     2797        {
     2798            *piNativeRc = rcNt;
     2799            rc = VINF_SUCCESS;
     2800        }
     2801        else if (NT_SUCCESS(rcNt))
     2802            rc = VINF_SUCCESS;
     2803        else
     2804            rc = RTErrConvertFromNtStatus(rcNt);
     2805    }
     2806    else
     2807    {
     2808        if (piNativeRc)
     2809            *piNativeRc = STATUS_NO_MEMORY;
     2810        rc = VERR_NO_MEMORY;
     2811    }
     2812
     2813    /* Relase the context. */
     2814    cRefs = ASMAtomicDecU32(&pCtx->cRefs);
     2815    Assert(cRefs < _4K);
     2816    if (cRefs == 0)
     2817        supdrvNtIoCtlContextDestroy(pCtx);
     2818
     2819    return rc;
    25602820}
    25612821
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