DriverKit IOUserSerial Driver

Hello everyone. After a lot of research and some tests from various sources, I have actually built a small SerialDriverKit IOUserSerial driver. Unfortunately, the documentation on the official sites is tight-lipped and very thin. At least I have a running driver instance. Now my request and question: Can anyone give me a tip on how to get the data from the serial client? I have already called IOUserSerial::ConnectQueues(...) in the IOUserSerial::Start() method and I got the IOMemoryDescriptors for interrupt, RX and TX to my driver instance. I tried to get access to the memory in the method IOUserSerial::TxDataAvailable() with IOMemoryDescriptor::CreateMapping(...).

Unfortunately, no data is coming in. It's always 0x00. Here is the OS log:

kernel: (org.eof.tools.VSPDriver.dext) <private> kernel: (org.eof.tools.VSPDriver.dext) [VSPDriver] init called. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] constructor called. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriver] start called. kernel: (org.eof.tools.VSPDriver.dext) IOUserSerial::<private>: 40 0x600000da4058 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] Start called. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] Connect INT/RX/TX buffer. kernel: (org.eof.tools.VSPDriver.dext) IOUserSerial::<private>: 59 0x600000da4058 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] prepare TCP socket. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriver] driver started successfully. kernel: DK: VSPDriver-0x100000753::start(IOUserResources-0x100000116) ok ... ... some client serial setup stuff ... kernel: (IOUserSerial) IOUserSerial::hwResetFIFO: 1076 ==>0 kernel: (IOUserSerial) IOUserSerial::hwResetFIFO: 1076 <== kernel: (IOUserSerial) IOUserSerial::hwResetFIFO: 1076 locklevel = 1 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriver] HwResetFIFO called. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] HwResetFIFO called. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] HwResetFIFO: tx=0 rx=1 kernel: (IOUserSerial) IOUserSerial::hwResetFIFO: 1076 ==>0 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriver] TxDataAvailable called. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable called. kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: address=0x104c22000 length=16384 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: debug TX buffer kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00 kernel: (org.eof.tools.VSPDriver.dext) [VSPDriverPrivate] TxDataAvailable: TX> 0x00

Answered by DTS Engineer in 823975022

I’m gonna ask Kevin to wade in here, because he knows the DriverKit side of this much better than I do.

I'm here...

SO, let me start with some more "foundational" guidance. Inside the DriverKit.iig file, you'll find methods declared in two different ways:

  • Standard declaration:
	virtual void            RxDataAvailable();
  • "LOCAL" declaration:
	virtual void            RxFreeSpaceAvailable() LOCAL;

The "LOCAL" keyword is critical here. As the documentation puts it:

"Tells the system that the method runs locally in the driver extension's process space."

AND:

"DriverKit adds this macro to methods that must run locally in your driver extension. A method tagged with this macro may still be called by a remote process such as the kernel. Don't add this macro to your own methods."

Unfortunately, the phrase "may still be called..." is somewhat misleading, as what we really meant was "will be called...". That is, the entire reason a method is tagged with "LOCAL" is to inform you that we need to implement it because we WILL be calling it.

That leads back to here:

Can anyone give me a tip on how to get the data from the serial client?

"ConnectQueues" is declared "LOCAL", so the system is going to be calling it, not necessarily "you". The answer for virtual terminals ends up looking something like:

kern_return_t
IMPL(<your calls name>, ConnectQueues)
{
	IOReturn err = ConnectQueues(ifmd, rxqmd, txqmd, in_rxqmd, in_txqmd,
			in_rxqoffset, in_txqoffset, in_rxqlogsz, in_txqlogsz, SUPERDISPATCH));

	assert(err == kIOReturnSuccess);

	IOAddressSegment seg;

	assert(!(*ifmd)->GetAddressRange(&seg));
	<your pointer to the control struct> = (SerialPortInterface*)seg.address;

	//track any other memory you want a reference to....
	
	return kIOReturnSuccess;
}

My question is, how can I obtain the data in the method IOUserSerial::TxAvailable which has been called by the OS

The SerialPortInterface struct that you saved a pointer to in "ConnectQueues" has the data about exactly where the serial port is in the ring buffers the other memory descriptors manage.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hello Kevin, ignore the last post. Some time it's difficult to see the right tree in the forrest. The show stop was a simple bug were the link and port IDs checked. Sorry. Best regards

Good! Glad to here you've gotten things working!

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hello Kevin, Me again :) The VSPDriver (Virtual Serial Port DEXT) project is, from my point of view, finished for now. Since I discovered that it is more than complicated to get my client app including the DEXT into the AppStore (Entitlements things), hence the request: If you could use the code at Apple and build this extension into the OS, that would certainly be helpful for many other (embedded/device) developers. The corresponding client app that controls the VSP Driver Extension is in the repository on GitHub. The code is certainly interesting for you too. Maybe you can build a developer tool app from it and integrate it into the OS (maybe under /System/CoreServices :-)

DriverKit IOUserSerial Driver
 
 
Q