VirtualBox

Changeset 51229 in vbox


Ignore:
Timestamp:
May 9, 2014 7:34:42 PM (10 years ago)
Author:
vboxsync
Message:

SUPDrv-win.cpp: Use the Fast I/O dispatch interface for noticeably reducing ioctls overhead on windows. For the run-guest-code type of ioctls we're ~2.5 times faster. With the normal requests its about 1.8 times faster. (using tstInt and debug builds for the measuring)

File:
1 edited

Legend:

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

    r49855 r51229  
    6565/** Win Symlink name for user access. */
    6666#define DEVICE_NAME_DOS_USR     L"\\DosDevices\\VBoxDrvU"
     67
     68/** Enables the fast I/O control code path. */
     69#define VBOXDRV_WITH_FAST_IO
    6770
    6871
     
    109112static NTSTATUS _stdcall   VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    110113static NTSTATUS _stdcall   VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
     114#ifdef VBOXDRV_WITH_FAST_IO
     115static BOOLEAN  _stdcall   VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
     116                                                        PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
     117                                                        PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj);
     118#endif
    111119static NTSTATUS _stdcall   VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    112120static int                 VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
     
    132140/** Pointer to the user device instance. */
    133141static PDEVICE_OBJECT g_pDevObjUsr = NULL;
     142#ifdef VBOXDRV_WITH_FAST_IO
     143/** Fast I/O dispatch table. */
     144static FAST_IO_DISPATCH const g_VBoxDrvFastIoDispatch =
     145{
     146    /* .SizeOfFastIoDispatch            = */ sizeof(g_VBoxDrvFastIoDispatch),
     147    /* .FastIoCheckIfPossible           = */ NULL,
     148    /* .FastIoRead                      = */ NULL,
     149    /* .FastIoWrite                     = */ NULL,
     150    /* .FastIoQueryBasicInfo            = */ NULL,
     151    /* .FastIoQueryStandardInfo         = */ NULL,
     152    /* .FastIoLock                      = */ NULL,
     153    /* .FastIoUnlockSingle              = */ NULL,
     154    /* .FastIoUnlockAll                 = */ NULL,
     155    /* .FastIoUnlockAllByKey            = */ NULL,
     156    /* .FastIoDeviceControl             = */ VBoxDrvNtFastIoDeviceControl,
     157    /* .AcquireFileForNtCreateSection   = */ NULL,
     158    /* .ReleaseFileForNtCreateSection   = */ NULL,
     159    /* .FastIoDetachDevice              = */ NULL,
     160    /* .FastIoQueryNetworkOpenInfo      = */ NULL,
     161    /* .AcquireForModWrite              = */ NULL,
     162    /* .MdlRead                         = */ NULL,
     163    /* .MdlReadComplete                 = */ NULL,
     164    /* .PrepareMdlWrite                 = */ NULL,
     165    /* .MdlWriteComplete                = */ NULL,
     166    /* .FastIoReadCompressed            = */ NULL,
     167    /* .FastIoWriteCompressed           = */ NULL,
     168    /* .MdlReadCompleteCompressed       = */ NULL,
     169    /* .MdlWriteCompleteCompressed      = */ NULL,
     170    /* .FastIoQueryOpen                 = */ NULL,
     171    /* .ReleaseForModWrite              = */ NULL,
     172    /* .AcquireForCcFlush               = */ NULL,
     173    /* .ReleaseForCcFlush               = */ NULL,
     174};
     175#endif /* VBOXDRV_WITH_FAST_IO */
    134176
    135177
     
    219261{
    220262    /*
     263     * Sanity checks.
     264     */
     265#ifdef VBOXDRV_WITH_FAST_IO
     266    if (g_VBoxDrvFastIoDispatch.FastIoDeviceControl != VBoxDrvNtFastIoDeviceControl)
     267    {
     268        DbgPrint("VBoxDrv: FastIoDeviceControl=%p instead of %p\n",
     269                 g_VBoxDrvFastIoDispatch.FastIoDeviceControl, VBoxDrvNtFastIoDeviceControl);
     270        return STATUS_INTERNAL_ERROR;
     271    }
     272#endif
     273
     274    /*
    221275     * Create device.
    222276     * (That means creating a device object and a symbolic link so the DOS
     
    254308                /* more? */
    255309
     310#ifdef VBOXDRV_WITH_FAST_IO
     311                /* Fast I/O to speed up guest execution roundtrips. */
     312                pDrvObj->FastIoDispatch = (PFAST_IO_DISPATCH)&g_VBoxDrvFastIoDispatch;
     313#endif
     314
    256315                /* Register ourselves for power state changes. */
    257316                UNICODE_STRING      CallbackName;
     
    428487
    429488
     489#ifdef VBOXDRV_WITH_FAST_IO
     490/**
     491 * Fast I/O device control callback.
     492 *
     493 * This performs no buffering, neither on the way in or out.
     494 *
     495 * @returns TRUE if handled, FALSE if the normal I/O control routine should be
     496 *          called.
     497 * @param   pFileObj            The file object.
     498 * @param   fWait               Whether it's a blocking call
     499 * @param   pvInput             The input buffer as specified by the user.
     500 * @param   cbInput             The size of the input buffer.
     501 * @param   pvOutput            The output buffer as specfied by the user.
     502 * @param   cbOutput            The size of the output buffer.
     503 * @param   uFunction           The function.
     504 * @param   pIoStatus           Where to return the status of the operation.
     505 * @param   pDevObj             The device object..
     506 */
     507static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
     508                                                     PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
     509                                                     PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
     510{
     511    PSUPDRVDEVEXT   pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
     512    PSUPDRVSESSION  pSession = (PSUPDRVSESSION)pFileObj->FsContext;
     513
     514    /*
     515     * Check the input a little bit.
     516     */
     517    if (!pSession)
     518    {
     519        pIoStatus->Status      = STATUS_INVALID_PARAMETER;
     520        pIoStatus->Information = 0;
     521        return TRUE;
     522    }
     523
     524    /*
     525     * Deal with the 2-3 high-speed IOCtl that takes their arguments from
     526     * the session and iCmd, and does not return anything.
     527     */
     528    if (   (   uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
     529            || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
     530            || uCmd == SUP_IOCTL_FAST_DO_NOP)
     531        && pSession->fUnrestricted == true)
     532    {
     533        int rc = supdrvIOCtlFast(uCmd, (unsigned)(uintptr_t)pvInput/* VMCPU id */, pDevExt, pSession);
     534        pIoStatus->Status      = RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
     535        pIoStatus->Information = 0; /* Could be used to pass rc if we liked. */
     536        return TRUE;
     537    }
     538
     539    /*
     540     * The normal path.
     541     */
     542    NTSTATUS    rcNt;
     543    unsigned    cbOut = 0;
     544    int         rc = 0;
     545    Log2(("VBoxDrvNtFastIoDeviceControl(%p): ioctl=%#x pvIn=%p cbIn=%#x pvOut=%p cbOut=%#x pSession=%p\n",
     546          pDevExt, uCmd, pvInput, cbInput, pvOutput, cbOutput, pSession));
     547
     548#ifdef RT_ARCH_AMD64
     549    /* Don't allow 32-bit processes to do any I/O controls. */
     550    if (!IoIs32bitProcess(NULL))
     551#endif
     552    {
     553        /*
     554         * In this fast I/O device control path we have to do our own buffering.
     555         */
     556        /* Verify that the I/O control function matches our pattern. */
     557        if ((uCmd & 0x3) == METHOD_BUFFERED)
     558        {
     559            /* Get the header so we can validate it a little bit against the
     560               parameters before allocating any memory kernel for the reqest. */
     561            SUPREQHDR Hdr;
     562            if (cbInput >= sizeof(Hdr) && cbOutput >= sizeof(Hdr))
     563            {
     564                __try
     565                {
     566                    RtlCopyMemory(&Hdr, pvInput, sizeof(Hdr));
     567                    rcNt = STATUS_SUCCESS;
     568                }
     569                __except(EXCEPTION_EXECUTE_HANDLER)
     570                {
     571                    rcNt = GetExceptionCode();
     572                }
     573            }
     574            else
     575                rcNt = STATUS_INVALID_PARAMETER;
     576            if (NT_SUCCESS(rcNt))
     577            {
     578                /* Verify that the sizes in the request header are correct. */
     579                ULONG cbBuf = RT_MAX(cbInput, cbOutput);
     580                if (   cbInput  == Hdr.cbIn
     581                    && cbOutput == Hdr.cbOut
     582                    && cbBuf < _1M*16)
     583                {
     584                    /* Allocate a buffer and copy all the input into it. */
     585                    PSUPREQHDR pHdr = (PSUPREQHDR)ExAllocatePoolWithTag(NonPagedPool, cbBuf, 'VBox');
     586                    if (pHdr)
     587                    {
     588                        __try
     589                        {
     590                            RtlCopyMemory(pHdr, pvInput, cbInput);
     591                            if (cbInput < cbBuf)
     592                                RtlZeroMemory((uint8_t *)pHdr + cbInput, cbBuf - cbInput);
     593                            rcNt = STATUS_SUCCESS;
     594                        }
     595                        __except(EXCEPTION_EXECUTE_HANDLER)
     596                        {
     597                            rcNt = GetExceptionCode();
     598                        }
     599                    }
     600                    else
     601                        rcNt = STATUS_NO_MEMORY;
     602                    if (NT_SUCCESS(rcNt))
     603                    {
     604                        /*
     605                         * Now call the common code to do the real work.
     606                         */
     607                        rc = supdrvIOCtl(uCmd, pDevExt, pSession, pHdr);
     608                        if (RT_SUCCESS(rc))
     609                        {
     610                            /*
     611                             * Copy back the result.
     612                             */
     613                            cbOut = pHdr->cbOut;
     614                            if (cbOut > cbOutput)
     615                            {
     616                                cbOut = cbOutput;
     617                                OSDBGPRINT(("VBoxDrvNtFastIoDeviceControl: too much output! %#x > %#x; uCmd=%#x!\n",
     618                                            pHdr->cbOut, cbOut, uCmd));
     619                            }
     620                            if (cbOut)
     621                            {
     622                                __try
     623                                {
     624                                    RtlCopyMemory(pvOutput, pHdr, cbOut);
     625                                    rcNt = STATUS_SUCCESS;
     626                                }
     627                                __except(EXCEPTION_EXECUTE_HANDLER)
     628                                {
     629                                    rcNt = GetExceptionCode();
     630                                }
     631                            }
     632                            else
     633                                rcNt = STATUS_SUCCESS;
     634                        }
     635                        else if (rc == VERR_INVALID_PARAMETER)
     636                            rcNt = STATUS_INVALID_PARAMETER;
     637                        else
     638                            rcNt = STATUS_NOT_SUPPORTED;
     639                        Log2(("VBoxDrvNtFastIoDeviceControl: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
     640                    }
     641                    ExFreePoolWithTag(pHdr, 'VBox');
     642                }
     643                else
     644                {
     645                    Log(("VBoxDrvNtFastIoDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
     646                         uCmd, Hdr.cbIn, Hdr.cbOut, cbInput, cbOutput));
     647                    rcNt = STATUS_INVALID_PARAMETER;
     648                }
     649            }
     650        }
     651        else
     652        {
     653            Log(("VBoxDrvNtFastIoDeviceControl: not buffered request (%#x) - not supported\n", uCmd));
     654            rcNt = STATUS_NOT_SUPPORTED;
     655        }
     656    }
     657#ifdef RT_ARCH_AMD64
     658    else
     659    {
     660        Log(("VBoxDrvNtFastIoDeviceControl: WOW64 req - not supported\n"));
     661        rcNt = STATUS_NOT_SUPPORTED;
     662    }
     663#endif
     664
     665    /* complete the request. */
     666    pIoStatus->Status = rcNt;
     667    pIoStatus->Information = cbOut;
     668    return TRUE; /* handled. */
     669}
     670#endif /* VBOXDRV_WITH_FAST_IO */
     671
     672
    430673/**
    431674 * Device I/O Control entry point.
     
    441684
    442685    /*
    443      * Deal with the two high-speed IOCtl that takes it's arguments from
    444      * the session and iCmd, and only returns a VBox status code.
    445      *
    446      * Note: The previous method of returning the rc prior to IOC version
    447      *       7.4 has been abandond, we're no longer compatible with that
    448      *       interface.
     686     * Deal with the 2-3 high-speed IOCtl that takes their arguments from
     687     * the session and iCmd, and does not return anything.
    449688     */
    450689    ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
     
    455694    {
    456695        int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
    457 
    458 #if 0   /* When preemption was not used i.e. !VBOX_WITH_VMMR0_DISABLE_PREEMPTION. That's no longer required. */
    459         /* Raise the IRQL to DISPATCH_LEVEL to prevent Windows from rescheduling us to another CPU/core. */
    460         Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    461         KIRQL oldIrql;
    462         KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
    463         int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
    464         KeLowerIrql(oldIrql);
    465 #endif
    466696
    467697        /* Complete the I/O request. */
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