NOTE: This article appeared in The NT Insider in early 2014. We provide it here as it was originally written.
You’re working at some company. They’ve decided to support a new device on Windows. Or perhaps they want to add some features to an existing device that’s already supported by Windows. Or, just maybe your company needs to collect some information from the operating system, which is only available from kernel-mode. Regardless of which of these describes your situation, somebody is going to need to write a driver to accomplish this goal.
Since you’re a clever guy and eager to learn new stuff, your managertroid asks you if you’d like to write the driver. You say “Sure!” The problem? You’ve never written a driver for Windows before. Where do you begin? Where can you find a good introduction to Windows driver development? Are there any tutorials on writing Windows drivers that will be helpful?
Believe it or not, one of the most commonly asked questions we receive here at OSR is “How do I write a driver for Windows?” You’d think the answer would be simple. And sometimes it is. But, all too often, the answer is not only non-obvious, it’s fraught with complexity.
The answers to the question, “How do I write a driver for my device on Windows” come in three categories:
- What you need to know
- What development tools (and stuff) you need
- What driver model to use
We’ll describe each of these in individual sections, below.
What You Need To Know
The things you need to know fall into two categories:
- Personal background about the Windows operating system and devices that’ll allow you to readily learn about how to write Windows drivers.
- Technical information about the hardware device you need to write your driver for (if you’re writing a driver for a hardware device).
Items in the first category, personal background knowledge, are actually pretty simple. To be able to write drivers for Windows and not just confuse yourself, you need to have at least general knowledge of computer operating systems and Windows in particular. You probably know most of what you need if you took a general OS Concepts class when you were in school. If you understand about devices, registers, interrupts, virtual memory, scheduling, multi-threaded programming, reentrancy, and concurrency issues… you’re more than half-way there. You can pick-up the Windows-specific information you need from doing a bit of reading. Please don’t skip this step. We spend almost two days in the 5-day driver seminar we teach here at OSR just discussing Windows OS and I/O subsystem architecture. So, it’s important.
Also, if you’re not familiar with programming on Windows systems from a user perspective (maybe you’ve been working in Linux all your life… if so, first of all, I’m sorry… but I digress) it would also be helpful to know a bit about Windows I/O fundamentals.
If you need to brush-up on your OS concepts, would like to know more about Windows OS concepts in particular, or you’d like to learn more about how I/O is performed in Windows, we have some reading suggestions in the Sidebar labeled Understanding Windows OS and I/O Concepts (See below). Doing that reading should set you up well for your task for writing Windows drivers.
How do you learn basic OS concepts and Windows architecture? There are a couple of good books to which we regularly refer our students. These are:
Windows Internals 6th Edition — Part 1
(Russinovich, Solomon, Ionescu) (Microsoft Press)
This is the basic description of Windows OS Architecture. Everyone in the world of Windows has read it at some time. When you read the following chapters, you may just skip the exercises shown or try a few if they sound interesting to you… it’s your choice. –
- Chapter 1: Concepts and Tools (whole chapter)
- Chapter 2: System Architecture (whole chapter)
- Chapter 3: System Mechanisms (Up to but not including section entitled Advanced Local Procedure Calls)
Windows System Programming 4th Edition
(Johnson M. Hart) (Addison-Wesley Microsoft Technology Series)
If you’re going to write device drivers, it probably makes sense to understand something about how to write Windows programs. If you’ve worked on Unix, and you’ve never written a program on a Windows system, this book will give you a lot of the information you’ll need.
- Chapter 1: Getting Started With Windows (whole chapter)
- Chapter 2: Using the Windows File System and Character I/O (whole chapter)
- Chapter 4: Exception Handling (whole chapter)
- Chapter 14: Asynchronous Input/Output and Completion Ports
One other thing you’ll need to know in terms of personal background is something about the hardware architecture that’s typical of the platform on which your hardware will be running. Whether the device you’re writing the driver for will run on PC (desktop to server) systems or used exclusively in an ARM SoC system, knowing something about the hardware environment – such as common buses and hardware concepts – that are unique to that platform would be valuable. You don’t need to know a lot. We’re not saying you need to be a hardware designer. We’re just saying knowing, for example, the basic concepts of PCIe or USB or SPI or whatever bus your device connects to will help speed you on your way as you write your driver.
About Your Hardware
If you’re writing a driver to support a hardware device on Windows, you’ll need the hardware specifications for the device you’ll be supporting. The information you need usually takes the form of a “data sheet” (which is often more like a book than a single sheet of paper) that describes the register-level interface to your device. Your hardware designer can give this to you. You need the specifics of your device, by the way. If the device you’ll be writing your driver for is implemented using some sort of PLD like an FPGA, don’t let your hardware designer simply point you off to the hardware spec for the PLD device (hardware designer waves her hand at you while saying: “Oh, we’re using an Arria II GX. Just go to Altera’s web site and download what you need. Bye.”). You need to know how the designer has implemented the register interface using the chosen PLD device, not the specs for the PLD itself.
Development Tools (and Stuff) You Need
Over the past few years, the tools used for Windows driver development have undergone nothing short of a revolution. Gone (well, mostly) are the days when you had to use special mystic project files and compile and link your code from the command line. Today, Windows driver development is fully integrated with Visual Studio.
At the current time (January 2014, Windows 8.1 was released a few months ago), driver development is supported in Visual Studio 2012 and Visual Studio 2013, Professional Edition or better. That means the “free for anybody to use” version of Visual Studio (Visual Studio Express Edition, or whatever they’re calling it now) cannot be used for driver development. So you will need to buy an MSDN and Visual Studio subscription. One very cool thing to note, however, is that you can use the 90-day trial versions of Visual Studio Professional 2013 and Visual Studio Ultimate 2013 that are available and free to download.
Once you have Visual Studio purchased and installed on your development machine, you’ll also need to install the Windows Driver Kit (WDK) add-in that supports driver development. This is a separate, but free (yay!), download from Microsoft (no MSDN subscription necessary). Search “Get Windows Driver Kit” using your search engine of choice.
Visual Studio and the WDK together provide everything you need to create driver projects, and to compile, link, and even debug Windows drivers. After you’ve successfully installed Visual Studio and the WDK, you can very easily build a simple driver demo project. You don’t even need any hardware! Just select “New Project” and within Visual C++ select the Windows Driver project category. Within this category select Kernel Mode Driver (KMDF). Click OK and Visual Studio will generate a simple starter or demo driver project for you that doesn’t require any specific hardware. This driver will successfully build, and can even be installed on a test machine. Yup, it really is that simple.
Ah, test machines. That’s probably something we should discuss. Driver development on Windows requires two Windows systems. One system where you run Visual Studio, do your development, and run the debugger. And a second, separate, system on which you run your driver. The Windows kernel debugger, running on your Development System, controls your Target System (where the driver you’re developing is running) via a remote connection that can be either a serial port, 1394, the network, or even in some cases USB. See Figure 1.
If you think about it, this makes good sense: Driver and hardware errors can quite easily destabilize or even crash a system. So you certainly don’t want to be running your new and potentially buggy driver on the same system on which you’re editing your source code files and doing your development.
In many cases, the second system can be a virtual machine. Using a virtual machine is acceptable when you’re writing a driver (such as a filter driver or a file system) that doesn’t directly access any hardware. But if your driver talks to real hardware, you’ll need a real, physical, second machine to use as your Target System. This is true even when you’re building a driver for something like a USB device, when the VM host you’re using allows you to assign access to the device exclusively to a given VM.
We mentioned the Windows kernel debugger. This debugger is named WinDbg (which almost everyone pronounces as “wind bag”, by the way). The debugger is included in the Windows Driver Kit and is automatically installed on your system when you install the WDK. It’s the debugger you’ll use as part of developing and testing your driver. It’s very similar to the user-mode debugger in Visual Studio, and has most of the same features.
There are several options available for using WinDbg for debugging your driver. One option is to use WinDbg directly within Visual Studio, through the interface provided by the WDK. While this pretty much works, here at OSR we don’t recommend this. Our experience is that trying to use WinDbg from within Visual Studio creates more complications than it’s currently worth. Instead, we recommend that you run WinDbg directly from your development machine, outside of Visual Studio. This allows you to use Visual Studio for driver development, which is what it’s best at, and use WinDbg directly for debugging, which is what WinDbg is best at.
Before you can use WinDbg to debug your driver, you’ll need to enable kernel debugging on the target system. Fortunately, it’s easy and very well documented (thank you, WDK doc writers). Search “Setting Up Kernel-Mode Debugging Manually” in your search engine of choice for the steps.
One quick note about debugging. Do not, under any circumstances, try to develop your driver without setting up WinDbg. For some reason, there are folks who’ve been fooled into thinking they can use something like the Microsoft DebugView utility, which allows DbgPrint statements (the kernel-mode equivalent of printf or OutputDebugString) from your driver to be viewed on your system, as their sole tool for driver development. While DebugView can be useful at times, we can guarantee that it is no substitute for having a debugger that allows you to set breakpoints, single step, and change the contents of structure fields and local variables. While setting up WinDbg for the first time can sometimes be annoying, we promise you it’ll be worth your effort in the long run. Yay, WinDbg!
The final thing you’ll need are the Windows Driver Kit Samples. These are example drivers, provided by Microsoft, that demonstrate how to write drivers of various kinds. They’re just like the typical sample code you download from MSDN: They are very useful and highly instructive, even if some of the code provided isn’t always exactly “the best.” Samples are provided for all sorts of hardware drivers, filter drivers, and software-only drivers. Heck, they even give you the source code to a few of the drivers that are part of the Windows OS… including sources for the FAT file system.
The samples are available as a separate download from Microsoft, and as with the WDK no MSDN subscription is required. Search “Windows hardware development samples” from your search engine of choice. You can download specific samples individually, or you can download the entire ZIP archive (about 100MB when this was written, including more than 160 sample drivers). We recommend you download the complete archive. Take your time and look through the samples. This will be time well spent.
So… now you have the background info you need, and you have all the stuff you need to develop Windows drivers. What’s the next step?
What Driver Model to Use
The actual development of a Windows driver starts with choosing what “driver model” to use for your driver’s implementation. Many folks find this step confusing. A driver model is an overall driver organization, including a set of APIs and entry points, which you’ll use when you write your code. Unlike some other operating systems that support a small number of driver models (“block” and “character”, for example) Windows has a wide number of driver models. The best driver model to choose is based on as many as three things. These are:
- The type of driver you’re writing: Hardware device, filter, or some other kind.
- If you’re writing a driver for a hardware device, the category (storage controller, sound card, graphics adapter, network card) of device.
- Developer preference
Now hear this: The choice of a driver model is the most important decision you’ll make about how your driver will be developed. And it’s a place where many people make the wrong decision and “go off the rails” – making their project much harder than it needs to be. So take some time to make this decision. Don’t simply Google around and find some trash example lying on a web site somewhere and start to hack it. Make the decision thoughtfully.
General Purpose Models
Broadly speaking, there are two Windows driver models that apply for general use, and some Windows driver models that apply to specific devices. For example, if you’re writing a driver for a local area network card, Windows has a specific model that is tailored specifically for this use and makes it maximally convenient to implement this type of driver. Likewise, if you’re writing a driver that supports streaming audio or streaming video, Windows has a specific model for these types of drivers. These are only two simple examples. Windows has specific models for lots of other device types as well.
Lacking a specific model for your device type, you can use one of the general-purpose models. The first general-purpose model is the Windows Driver Model (WDM). WDM is the old, historic, model for writing Windows drivers. Nobody should use this model anymore for writing new Windows drivers. Seriously. Nobody. It’s hard to use and filled with “traps” that have evolved over years to support backward compatibility guarantees. Trying to write a new WDM driver in the 21st Century will do nothing but make you hate life. Don’t do it. Enough said?
Much preferred over WDM is the Windows Driver Foundation (WDF). This is the second general-purpose driver model that Windows supports. WDF is a modern, pleasant, and (dare I say it) almost easy to use method for writing Windows drivers. Unless there’s a specific model that Microsoft recommends for the device, filter, or software-only driver you need to write, you’ll want to use WDF.
One interesting thing about WDF is that it actually comes in three flavors, called Frameworks:
- Kernel Mode Driver Framework – KMDF
- User Mode Driver Framework V1 – UMDF V1.x
- User Mode Driver Framework V2 – UMDF V2.0 (only applies to Windows 8.1 and later)
KMDF is the Kernel Mode Driver Framework. This is the model you’ll almost certainly want to use now and in the near future for any general-purpose Windows driver development project.
You’ll notice that there are two WDF Frameworks that allow you to write drivers in user-mode. Writing drivers in user mode is good, because if there’s a bug in your driver (let’s say, you deference a null pointer) your user-mode driver won’t crash the system the way it would if you wrote your driver in kernel mode. That’s certainly a very good thing, and contributes to nothing but customer satisfactions. So, why didn’t we recommend using UMDF for writing your drivers?
Using UMDF today is a problem. UMDF V1 is the older model. It’ll support devices running on Windows versions as old as Windows XP. But UMDF V1 uses an odd, difficult, programming pattern that’s based on COM (yes, the Component Object Model… that COM). Add to that the fact that UMDF V1 has more or less been put in “end of life” status by Microsoft, and you get a model that most people will want to avoid.
UMDF V2.0 is actually a terrific driver model. It uses 99% the same syntax as KMDF, but it runs in user mode, thus contributing to overall system stability. So why don’t we recommend using UMDF V2.0 today? Because UMDF V2.0 is currently only supported on Windows 8.1 or later. To be absolutely clear, this means that if you write a UMDF V2 driver, that driver can only be installed on systems that are running Windows 8.1 or more recent versions of Windows. In short, unless you only need to support Windows 8.1 or more recent systems, UMDF V2 isn’t really a viable choice. On the other hand, if you do only need to support Windows 8.1 or later (I don’t know, maybe you’re writing a driver for some sort of embedded system) then UMDF V2.0 could be a very good choice indeed.
Choosing the Best Model for Your Project
Confused? It wouldn’t be surprising if you are. We told you many people find this driver model stuff confusing. Fortunately, there are some simple rules that can help you decide the best driver model for your use. Here are those rules:
- Writing a driver for a hardware device? Check the Windows Hardware Certification Requirements for the type of device that you’ll be supporting. To do this, search for “Windows Hardware Certification Requirements: Devices”. If the type of device you’ll be supporting is listed, the Certification Requirements document will almost always specify the driver model you must use.Note that this guidance applies even if you don’t plan to apply for Windows Hardware Certification for your device and driver. The Certification Requirements will almost always point you in the direction of the best, easiest, most modern, and most supportable driver model that applies to your type of device.
- Writing a filter driver? A filter driver in Windows is a type of driver that monitors I/O operations going to a given device/driver in the system and intercepts those I/O operations. The purpose for intercepting those I/O operations might be to track them, measure them, or modify them. If you’re writing a filter for file systems (like for an antivirus product) or networks (such as you would write for a firewall product), there are specific driver models defined for these uses.
- Writing a software-only driver? For example, maybe you need to write a driver that collects data in kernel-mode. In this case, you probably want to write a software-only KMDF driver. Using what’s called the “legacy NT model” is also a good option. But from the viewpoints of your general knowledge and ease of support, KMDF is probably going to be the right choice.
- Are you writing a file system? Stop reading now. You almost certainly do not want to write a Windows file system. It’s really difficult. We know, because it’s one of the things we’ve done over the years here at OSR. Send us email. We’ll see if we can talk you out of it, and if not we’ll point you in the right direction. Seriously. No charge.
- Neither of the previous steps pointed you to a specific model. Do you need to support systems older than Windows 8.1? If you only need to support Windows 8.1 or later, the best model for you to use is probably UMDF 2.0.If you need to support systems older than Windows 8.1, then your best choice of driver model is probably KMDF.
There are a number of factors that contribute to the decision of which driver model is best for you. You can read more about this on MSDN. Search for the page titled “Choosing a driver model”. For the reasons we described above, we recommend for the present time you ignore Microsoft’s advice about preferring UMDF. UMDF V2.0 will be a great choice when it supports the majority of systems in the field (either because Microsoft decides to support UMDF 2 on systems older than Windows 8.1 or everyone is running Windows 8.1 or later). But until that time, everywhere you see UMDF recommended we suggest you choose KMDF instead.
That’s how you get started writing Windows drivers. Learn a bit about Windows architecture, get the tools, and choose a model for your driver.
Of course, there are lots of things we haven’t discussed in this short article. We haven’t discussed how to install your driver (you write something called an INF file), specific techniques for driver development with any of the models, or strategies for debugging your code. But we have to leave something to write about in future issues.
We hope the above has been useful, and provided a place to start. Happy driver writing!