Re: Mach RPCs between user space and a kext
Re: Mach RPCs between user space and a kext
- Subject: Re: Mach RPCs between user space and a kext
- From: Sam Vaughan <email@hidden>
- Date: Fri, 21 May 2004 11:09:34 +1000
Wow thanks for all that info Jim.
The reason I considered Mach RPC in the first place was that most of
the work I wanted to do in my kext was in the Mach part of the kernel.
This meant that I had to use Mach search paths and all the appropriate
Mach defines to make sure the macros and data structures in the headers
were the same in my code as they are in the running kernel. Including
BSD headers was pretty much impossible.
I realised that I was going to have to put in some BSD code, so I made
a separate target in my project to build a BSD library that is then
linked in to the kext. That target uses the Kernel.framework search
paths like most regular kext targets. Once I had the BSD target, it
made sense to take the path of least resistance and publish a sysctl
interface. I'm now passing a structure in to the kext via a
sysctlbyname call, then doing a copyout of all my data to a
user-specified address in the structure.
So I've dumped my MIG code for now, but it's good to know it's possible
for future reference!
Sam
On 21/05/2004, at 6:45 AM, Jim Magee wrote:
On May 18, 2004, at 9:38 PM, Sam Vaughan wrote:
What's not clear to me is how my kext would register the RPC services
it provides with the part of the kernel that accepts the calls from
user space.
There are two methods in which Mach IPC/RPC operates in the kernel.
The first method, I'll call it the "active listener method," behaves
much like user-state Mach IPC. A kernel thread can wait on a Mach
port for a message to arrive, handle it, and reply with a reply
message. This method isn't used much in today's kernel (the
ux_exception handler thread in BSD behaves this way). The
disadvantage of this method is that it requires a thread switch
between client and server. But the advantages are that port rights and
memory are managed just like at user-space, and it requires "no
hookup" into the kernel's IPC object dispatch mechanism.
The second method, I'll call it the "passive invocation method," hooks
into the middle the Mach IPC implementation for faster (but less
"cooked") invocation. Under this method, the Mach IPC implementation
determines that the destination is an "IPC kernel object." breaks off
its processing of the message just after the "copyin" phase, and
invokes the server in the context of the calling thread. As I said,
the primary advantage of this method is speed. Only half of a typical
IPC operation has been performed (there was a send, but no receive).
But for many, the passive nature (tying up and using the user thread
to invoke the kernel server) of the call is also an advantage. The
disadvantages include having to deal with an "uncooked (e.g.
un-received) message. The out-of-line memory is stored in short-hand
form (and must be manually "copied-in" to the kernel before you can
look at it). The port rights contained in the message are "naked"
(i.e. there is no port name, with a set of associated, but managed,
rights). Instead, you get a raw pointer to the port and you must
manage any rights associated with those ports implicitly. But the
biggest disadvantage from your question's perspective is that you must
get the port defined as an "IPC kernel object" in the first place.
You must "hook it up."
There is no mechanism in place for random kernel extensions to "hook
up" new IPC kernel objects (they are statically referenced in
xnu/osfmk/kern/ipc_kobject.c). So, you must leverage one of the
existing IPC kernel objects, or you must use the active listener
model. The extensible IPC kernel objects are the IOKit io_connect()
and io_service() objects. IOKit provides methods for exporting
services using these. But short of using IOKit, there is no way to
hook up a "passive" Mach port in a KEXT.
That being said - how do you export a port to user-space? Again,
IOKit provides a mechanism for doing this (the registry).
Also, what port should the user space code use when it issues the
RPC? The Kernel Programming doc says to look in bootstrap.h, but
this file is empty in Darwin 7.3.0.
What they should have said (I haven't looked it up to be sure), is to
look in <servers/bootstrap.h>. But these services aren't available IN
the kernel, only outside.
Can anyone point me to some sample code that uses Mach RPC to cross
the user-kernel boundary? The examples in Darwin such as
upl_commit_range() and friends simply call Mach from BSD, which isn't
really relevant to the issues I'm seeing.
Actually, upl_commit_range() is defined in <mach/upl.h> and is
published to user-space - although currently unused as a kernel-user
boundary interface (until the EMMI gets re-published to user-space,
there's not much use for a UPL out there).
--Jim
_______________________________________________
darwin-kernel mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/darwin-kernel
Do not post admin requests to the list. They will be ignored.