Well, now that the Windows 8 cat is mostly out of the bag, I shall start talking about a recent project of mine that interests me and might be interesting to others.

Several of the changes or new features in WDF, most notably the ability of UMDF drivers to access hardware and for KMDF to utilize the OS feature (new in Win8) to handle interrupts at passive level, presented a tough test challenge:  thorough testing with real hardware would require a lot of devices, configurations of those devices, and most of all, WDF drivers for those devices. Automating such tests means lots of systems configured with all of that- expensive, and still limiting how much testing you can get in over any period of time.

This makes simulation an attractive option, but as I looked into the available options, I kept hitting limits I didn't care for- most of which I cannot discuss.  So I'll skip to what I can discuss: I did what many old nerds do when faced with the need for something they can't have- I made my own.  That led to some fine understandings and experiences, some of which I hope to share.  So I'll break my self-imposed silence for a while and talk about my adventures in the land of simulation infrastructure.

A Few Basics 

I'll start off by talking about a few basic concepts and terms I expect I'll be elaborating on before I'm done with this series of articles.

Resources

Hardware devices require system resources, and the OS is responsible for administering those resources (hopefully in a fair and equitable manner, at least if you wish to encourage third party participation).  The resources of interest in Windows for my purposes are:

  • address ranges in the processors' I/O space (where the processor has separate I/O and memory spaces)- in Windows, these are termed "ports"
  • address ranges in memory space- the Windows term is "registers" (and yes, this used to confuse the heck out of me as a hardware engineer- because from that background, the words "port" and "register" are essentially synonyms).
  • Interrupt vectors, including any sharing of vectors between devices that agree to such sharing
  • Channel assignments for any system DMA controller.

Other resources Windows reports and manages, such as bus numbers, weren't going to be of interest.  DMA channels were only of interest initially because we wanted to make sure resource formats made it to UMDF drivers intact through the framework- but since System DMA now has more influence on ARM / tablet / phone platforms, and Windows 8 has new DDI to go with it, it makes a nice place for future expansion should I get a chance to continue with this little project...

Redirection

When a driver accesses device hardware, it executes an instruction on a processor, and that instruction causes the processor's circuitry to issue some electrical signals that are received by the device, which then responds to them in a similar fashion.  Now the same thing happens on every instruction, of course, since memory and even the other processors or cores on the same chip are themselves devices- but the key point here is that I/O takes place in a physical reality- in simulating, you want those same instructions (at some appropriate level of abstraction) to instead produce activity in the logic of your simulation code, and for the results of that simulation to manifest themselves back in a fashion that makes it seem there is a physical reality where there is none.  My apologies if that seemed overly abstract or even mystical :).  The point here is that for simulation to work, a means has to be provided for the code that expects to be accessing hardware to access your simulator, instead.  I use the term "redirection" to cover that process.

My colleagues and I (mostly I, so don't blame them for any of my bad ideas) considered a number of ways to do this.  Using virtualization features was very attractive, but schedule realities, compounded by current skill levels of those working on the project and the associated learning curve, made that infeasible.  So I went for a practical but not entirely attractive alternative, the basics of which are these:

  • where possible, OS calls related to hardware access made by a driver of simulated hardware would be detoured using Import Address Table hooks.  I know some people are not fans of such methods, but it reduces the code-level and binary-level impact of having to redirect.
  • Unfortunately, port and register access are not out-of-module calls (and hence capable of being detoured) on most platforms- so these would require "side-by-side" build of a driver where the macros were redefined into calls into a redirection component.
  • Since we were going to be building special simulation versions of drivers, I added some additional calls to those drivers to be made under #ifdef to make other aspects of the job easier- they correspond roughly to DriverEntry, DriverUnload, and the WDF Prepare and Release Hardware callbacks.
  • Finally, KMDF runtime had some support for interrupt simulation added during Windows 8 [and no, I'm not (AFAIK) permitted to tell you how it works].  It was added so DSF kernel simulators could be KMDF drivers- I just made use of the same mechanism.

Virtualization would have been nice, but it also would have required intervention on lab machines to enable the feature, and potential issues with it not being an available feature on all hardware. Is it is: we can now use simulated hardware on any machine running Windows. Our downside is having "production" and "test" versions of the drivers (including the UMDF redirector).  Our test versions can control also real hardware as-is (at a performance cost of figuring out whether a PDO is simulated or real hardware), but I've rarely needed to do that.

Arbitration and Bus Translation

As I said before, the OS administers these resources and their assignment.  Most modern hardware includes busses (PCI is quite prevalent, naturally, in its various forms) that can translate addresses or administer interrupts in ways that add to or enhance what the processor does.  So there is a rather elaborate dance between the Windows Kernel- particularly its plug-and-play "root arbiter", the Hardware Abstraction Layer, and these bus drivers to manage that process.  Doron Holan has some articles on this process, so you can refer to them for details.  For now, I'll say basically that the root parcels out processor resources, and the busses are responsible for claiming chunks of those and parceling them out (sort of like making a real estate subdivision from one big land purchase), and also for translating resources from the form their devices "see" (physically respond to and reply back on) to those the processor understands and uses.  I had originally hoped to not know much about this process- I later found out I had to- but I'm getting ahead of myself, and this is my story to tell.

In Windows, then the task breakdown in resource assignment is that a bus driver reports the resources required by a device, and the arbiter tree then determines which ones are then assigned to the device.  Those resources are reported to the device stack when it is started.  When a device is stoppee, removed, or surprise removed, the device's resources are returned to the pool of available resources at whatever level of the arbiter tree they came from.

Summing up

This is long enough for one effort, and my test OS installation has almost completed, so it's time to sum up.

For Windows 8, I developed a working (with some limitations imposed by schedule realities and my own time and abilities) hardware simulation infrastructure, and several device simulators that work with it- I got all of that working and into production, and it is currently used to test UMDF and KMDF in automated testing, including stress testing.  Some of the simulated devices are mimics of 'real" hardware, but most are devices I "designed" to let us test the hardware access capabilities of WDF to its fullest. 

There are more such tests and devices for UMDF than KMDF currently.  Why?  Because KMDF provides features for interrupts (and DMA, of course), but ports and registers are accessed using the existing kernel/HAL interfaces.- But UMDF now has DDI for accessing all of those resources.

It has been for me a challenging and interesting project- I'm glad I got a chance to do as much of it as I have (and I always see more that could be done- isn't that always the case?).  If the various powers that be, from divine to managerial, are willing, I'll be telling you more about it in the days to come.

Until next time, adieu.