Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

get from KernelMode to UserMode very quickly?

0 views
Skip to first unread message

name

unread,
Jun 22, 2008, 6:43:23 PM6/22/08
to
has anyone here every explored the following topic (with code sample) to
verify it works?

is this still possible to do in Windows XP?

is there any similar, newer, or even better "dirty tricks" to get from
KernelMode to UserMode very quickly?


found at: http://www.cmkrnl.com/arc-userapc.html

Usenet Archives
User mode APCs
Author: Anatoly Vorobey
Date: 1997/05/08
Forum: comp.os.ms-windows.programmer.nt.kernel-mode
Posted on: 1997/05/08
Message-ID:
Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode
Organization: Erol's Internet Services
Reply-To: mellon...@pobox.com
X-Received-On: 8 May 1997 11:43:05 GMT


Hi there,

The issue of notifying user-mode thread from a kernel-mode driver, or
calling a user-mode routine from same, is very often discussed here. The
usual solutions offered are: 1) a dedicated thread sending an IRP to the
driver which the driver leaves uncompleted and completes when it needs to
communicate information to the thread; and 2) signaling an event which can
be accessed in both user and kernel mode, with user-mode thread waiting on
it. Both these approaches have their drawbacks; in particular, they need a
dedicated thread waiting, and they're relatively slow - sometimes you _know_
you're in the right context, and you just need to tell something to the
user-mode thread or pass some information to it as soon as possible.

I've tried to find other ways of doing the same, being driven mostly by
curiosity, spirit of exploration and stubborness. I've found two other
mechanisms by which it is possible to make a thread call some specific
user-mode function:

1. User-mode APC (Asynchronous Procedure Call). The whole issue of APCs is
quite undocumented in the DDK. Actually, more informatiion about APCs can be
found in Win32 SDK help than in NT DDK help! That's because the whole
mechanism of completion routine-based I/O routines (like ReadFileEx(), etc.)
is quite transparently based on APC, and the SDK help says a few basic
things about APCs. They're also discussed briefly in the classic Helen
Custer's "Inside Windows NT".

The main problem with this approach is that according to the NT design
principles, a thread can receive a user-mode APC _only_ if it declares
itself alertable: either by waiting on a synchronization object with
alertable flag set on, or explicitly calling a certain function in ntdll.dll
to check whether it should be alerted. Since we _don't_ want our thread to
wait on anything (we may just as well use named event then) we're stuck. In
the code I give below, I overcome this problem in an undocumented and
somewhat dirty way; I'm still searching for more "clean" ways to do it.

When a user-mode APC is passed to a thread in this way, its routine be
called next time the thread runs in user-mode. If the thread already runs in
user-mode, the routine won't be invoked immediately, however; it'll be
called next time the thread _returns_ to user-mode from some kernel-mode
service. Usually that happens almost immediately since an active thread is
calling kernel-mode services all the time; in the worst case it'll happen
after the next clock tick, when clock tick procedure returns to user-mode.
The user-mode APC will not, however, interrupt any kernel-mode activity;
i.e. if the thread is waiting on an object, it won't be woken up; when it
wakes up by itself, however, it will receive the pending APC immediately.

2. KeUserModeCallback(). This is an undocumented function used by Win32
subsystem running in the kernel in NT 4.0 (win32k.sys). It's used when the
subsystem either needs to know some information stored in user-mode (for
example, in user32.dll's data), or needs to call a thread's window procedure
(for example, when you move your mouse, the subsystem eventually receives
notification of it in kernel mode, and it calls your window procedure with
WM_MOUSEMOVE message using this function). A catch here is that this
mechanism is predefined to call only some specified functions: one of
parameters to KeUserModeCallback() is an index to a special table from which
later in user mode an address to call is fetched. Still it's possible to
exploit this mechanism to call, _very_ quickly (much quicker than the APC,
named event or pending IRP mechanisms allow) an arbitrary routine of your
code. The catch here is that you _must_ be in your thread's context for this
to work; in this respect user-mode APC is better since you can freely send
it to any thread in the system.

Below is sample code that will send user-mode APC to the current thread,
calling an arbitrary user-mode routine and passing it three arbitrary
parameters. If you want to send an APC to your thread from arbitrary
context, you should capture its KTHREAD pointer by calling
KeGetCurrentThread() in _its_ context (say, when receiving a custom control
request from it and being top-level), and use it in a call to
KeInitializeApc later at any time.

Unfortunately, it will only work on x86 architecture due to one
machine-dependent line which modifies directly the KTHREAD structure. It
should, however, work on free/checked builds and SMP/uniprocessor machines
alike. It's taken right out of an article I'm completing which discusses in
detail both kernel-mode and user-mode APCs; I'm still uncertain whether I
should simply put it on the web or try to offer it to some paper magazines.

If you're interested, please try out this code and report to me whether it
works/ doesn't work for you and what happens if it doesn't. Note that I of
course disclaim any responsibility; your system might very well
crash/bugcheck, though I've tested this code for some time now and it's
always been working fine for me.


/* The APC structure is defined in ntddk.h */

/* this is KERNEL_ROUTINE for our APC; in particular, it gets
called when the APC is being delivered. Usually one of predefined
useful routines in the kernel are used for this purpose, but we
can't use any of them as none of them are exported. */

void MyRoutine(struct _KAPC *Apc,
PKNORMAL_ROUTINE norm_routine,
void *context,
void *SysArg1,
void *SysArg2)
{
ExFreePool(Apc);
return;
}

/* pointer to the APC we will create */

static struct _KAPC *apc;

/* KeInitializeApc() and KeInsertQueueApc() are the two functions
needed to send an APC; they're both exported but not prototyped
in the DDK, so we prototype them here. */

void KeInitializeApc(struct _KAPC *Apc, PKTHREAD thread,
unsigned char state_index,
PKKERNEL_ROUTINE ker_routine,
PKRUNDOWN_ROUTINE rd_routine,
PKNORMAL_ROUTINE nor_routine,
unsigned char mode,
void *context);


void KeInsertQueueApc(struct _KAPC *APC,
void *SysArg1,
void *SysArg2,
unsigned char arg4);

/* call this function when you need to send a user-mode APC to
the current thread. addr must be linear address of your user-mode
function to call:

void MyApcRoutine(ULONG arg1, ULONG arg2, ULONG arg3);
...
SendAddrToTheDriverUsingIoctl((ULONG)MyApcRoutine);

you should send it to the driver using your custom IOCTL.
arg1, arg2, arg3 are arbitrary ulong's which are passed to the
function residing at addr; this function should be prototyped as
receiving three parameters and returning void. */

void SendAPC(ULONG addr, ULONG arg1, ULONG arg2, ULONG arg3) {

PKTHREAD thread=KeGetCurrentThread();

/* this is self-explanatory */

apc=ExAllocatePool(NonPagedPool, sizeof(struct _KAPC));

/* Initialize the user-mode APC */

KeInitializeApc(apc, thread, 0,
(PKKERNEL_ROUTINE)&MyRoutine, 0,
(PKNORMAL_ROUTINE)addr, 1, (PVOID)arg1);

/* Insert it to the queue of the target thread */

KeInsertQueueApc(apc, (PVOID)arg2, (PVOID)arg3, 0);

/* Mark the current thread as alertable to force it to deliver
the APC on the next return to the user-mode.
NOTE: severely undocumented code here! */

*((unsigned char *)thread+0x4a)=1;
}


That's about it. I'll be very grateful to hear comments, corrections,
additions or flames from you. Questions are always welcome.

Yours,
Anatoly.

--
Anatoly Vorobey,
mel...@pobox.com http://pobox.com/~mellon/
"Angels can fly because they take themselves lightly" - G.K.Chesterton

Don Burn

unread,
Jun 22, 2008, 7:22:15 PM6/22/08
to
Why do you think you need this? I've encountered more crap code using
various hacks to notify user space than I want to remember and in every case
I have had a chence to test things, I found that dumping the "super fast"
model for the normal inverted call has never impacted the overall
performance of the app/driver combination. I'm sure there are cases where
it is justified, but they are rare, especially as processors continue
getting faster.


--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply


"name" <m...@myplace.com> wrote in message
news:fAA7k.25297$Jx.19057@pd7urf1no...

name

unread,
Jun 23, 2008, 1:33:39 PM6/23/08
to
Well, I did not intend to strike a nerve with anyone here! But if I did,
I'm sorry that happened.

Not all programmers are skilled in device driver composing. So I think
short-cuts, or hacks, back to user mode do have a certain allure.

Getting into (or notifying) the user mode thread that got was interrupted
(as quickly as possible) lets a programmer adjust the response to an
interrupt dynamically. Some specialty I/O is like that, where you get some
input bytes (or serial stream)coming at the CPU at unknown speed,
synchronization, framing; sometimes needing some quick simple
packing/unpacking and/or serialize/de-serialize, data conversion, etc.

Another common type of input is signals which are frequency or time-domain
shifted/encoded, so every interrupt needs a accurate timestamp associated
right away, which should be saved for analysis/decoding by the user mode
application.

Maybe the thing to ask then should be: What tools and information have
"evolved" recently, which can make device driver writing as easy as
application writing? As long as it remains a "black-art", hacks and crap
code will be attempted! Many of the Driver Wizard programs have faded away,
and I find only Jungo and Rapid Driver remain with any significant presence.
The choices are down from 1/2 dozen back in the late 90's, to just these 2;
and what they offer has not advanced much in the last decade it seems? A
typical applications programmer still cannot ramp up to Device Driver skill
level in mere days, which I don't think is unrealistic to expect, IF a
really good DDK was offered that included extensions to the familiar and
popular IDE's like Visual Studio, C+ Builder, or Delphi.


"Don Burn" <bu...@stopspam.windrvr.com> wrote in message
news:eshWR7L1...@TK2MSFTNGP03.phx.gbl...

Don Burn

unread,
Jun 23, 2008, 2:41:44 PM6/23/08
to
Well you first question was asking for techniques that are on the high edge
of the driver world, now the questions have moved quite a bit. First on
your example needs, sorry but I will repeat the mantra said often in the
Windows driver forums "Windows is not a real time OS". So if you really
have needs like your examples, find another system or get one of the real
time extensions that run under Windows.

As far as the "black art" look at Windows Driver Framework. This removes
much of the pain of driver writing in Windows and can make it easier. I
have never encountered "Rapid Driver" but Jungo and some of the other
toolkits no longer supported, I keep getting requests for quotes from people
who need their driver rewritten to something more standard. The common
reasons are:

1. The latest OS is not supported and won't be for some time.
2. Some feature of the OS is not supported and it is hard to use it in
the framework.
3. The framework had enough prolblems that people wanted a solid
driver, and decided it was time to replace the stuff they had.


--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply


"name" <m...@myplace.com> wrote in message

news:T7R7k.22521$kx.3756@pd7urf3no...

0 new messages