Windows""CE6"" now supports running drivers inside a user-modedriver host, udevice.exe. Our goal has been to support kernel drivers to work 鈥渏ust-as-they-are in user mode; though, some security restrictions applyas discussed below. The good news is that we managed to keep the overall usermode driver development experience and the driver interfaces exactly the sameas the one for kernel mode drivers.

User-mode drivers work prettymuch the same as kernel-mode drivers: an application calls""ActivateDevice""(Ex) and""DeactivateDevice"" on the driver. The device manager willcheck registry settings to see if the driver is supposed to be loaded in usermode. You can also use registry settings to specify an instance "ID"of udevice.exe to use, if you want multiple user-mode drivers to load into thesame process.


For example, there is oneuser-mode driver group with ID 3. Multiple drivers load into this group. If youlook inside the ""CE6""%_WINCEROOT%\public\common\oak\files\common.reg (an unprocessed version of whatyou get in your release directory), you'll see how this group is created and afew drivers that belong to it.


[HKEY_LOCAL_MACHINE\Drivers\ProcGroup_0003]

"ProcName"="udevice.exe"

"ProcVolPrefix"="$udevice"


; Flags==0x10 is DEVFLAGS_LOAD_AS_USERPROC

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Ethman]

"Flags"=dword:12

"UserProcGroup"=dword:3


[HKEY_LOCAL_MACHINE\Drivers\Console]

"Flags"=dword:10

"UserProcGroup"=dword:3


[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SIP]

"Flags"=dword:10

"UserProcGroup"=dword:3


If you don't specify aprocess group, your driver will be launched inside a unique instance ofudevice.exe.


The device manager creates areflector service object to help the user-mode driver do its job. The reflectorservice launches udevice.exe, mounts the specified volume and registers thefile system volume ""APIs"" for communicating with thedriver. Communication between applications and the user mode driver pass throughthe reflector, which helps with buffer marshalling. The reflector also assiststhe user-mode driver with operations that user-mode code is not normallyallowed to make, like mapping physical memory; more on this later.


It is our goal that driversshould be as close to 100% portable between kernel and user mode as possible.However, kernel code will always be more privileged than user code will be.Taking advantage of the increased kernel capabilities will make yourkernel-mode driver impossible to port to user mode.


What are some of theincompatibilities you need to know about? What are the security restrictionsthat apply to user mode drivers?


Firstly, user-mode driverscannot write back pointer parameters asynchronously. I take it a step furtherand say that user-mode drivers cannot operate on caller memory asynchronously.That you're better off keeping such drivers in kernel mode for now, orrestructuring their communication with the caller so that nothing isasynchronous.


Another detail you should knowabout is that user-mode drivers cannot receive embedded pointers from thekernel. If you're writing a driver that talks to kernel-mode drivers, and thosekernel-mode drivers pass you embedded pointers, then your driver may have nochoice but to run in kernel mode. If you can reorganize the communicationbetween drivers, you may be able to "flatten" the structure so thatall the data is stored directly in the IN and OUT buffers instead of referencedvia embedded pointers. That said, if you are sure that only user mode processeswill call your user mode driver, then you do not need to worry about flatteningembedded buffers though, you better be absolutely sure that nokernel mode driver will call into your user mode driver ever.


Thirdly, there are some""APIs"" which used to require trust that now are (mostly)blocked against use in user mode. One notable example is""VirtualCopy"", and its wrapper function""MmMapIoSpace"". Most user-mode code cannot call"VirtualCopy". User-mode drivers can, with a little help from thereflector. The reflector can call ""VirtualCopy"" on behalfof a user-mode driver, but it will not do so unless it knows the driver isallowed to use the addresses it's copying. Under each driver setup entry in theregistry, there are ""IOBase"" and""IOLen"" keys that we use to mark physical memory. Whenyour driver calls ""VirtualCopy"", the reflector will checkthese values to make sure your driver is allowed to access the physicaladdress. For example, the serial driver might specify a physical address likethis:


[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial]


"IoBase"=dword:02F8

"IoLen"=dword:8


If you have just one bufferto copy, use DWORD values. Use multi-strings to specify multiple base addressesand sizes.


[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial]


"IoBase"=multi_sz:"2f8","3f6"

"IoLen"=multi_sz:"8","2"


Since only privilegedapplications can write to this part of the registry, the registry keys shouldprotect against unprivileged code trying to gain access to these addresses.


Notable""APIs"" that user-mode code cannot call:


* VM APIs: ""VirtualCopy[Ex],LockPages[Ex], CreateStaticMapping""

* Interrupt APIs:""InterruptInitialize, InterruptDone, LoadIntChainHandler""

* You cannot install IISR directly, though youcan install GIISR via the reflector. (GIISR exposes well known interfaces andthe reflector can do the required checks on these calls.)

* OAL ""IOCTLs"" that are notexplicitly permitted by the kernel


And lastly, Call-backs from auser-mode driver to any process are also prohibited. The most importantrepercussion of this is, if you move a bus driver to user mode, you'd have tomove the client drivers to user mode too. You can't have the client driver inthe kernel since you cannot call back into the kernel mode client driver fromthe user mode bus driver. You may want to put the bus driver and all of itsclient drivers in the same udevice.exe instance, so that the callbacks are allwithin a single process. Again that said, you can easily move the client driverto user mode and keep the bus driver in kernel mode without any problems sincethe kernel mode bus driver can call back to the user mode client driver via theuse of ""CeDriverCallback"" API.


In effect, if your driver issimple and does not deal with the restrictions discussed above, you can easilymove your driver back and forth between user and kernel space by simplytweaking a Registry Key Setting.