Device Driver Stacks: Maybe BSD Can Do More With Less
The Problem
For open source and hobby operating systems, getting a handle on device support can be a significant barrier to gaining enough traction to sustain the project. From the start, there’s already an enormous amount of devices of all categories that need support. In most cases, projects tend to not have enough developers to focus on developing drivers for every user’s hardware. Projects tend to already have their hands full with developing solutions, while being woefully understaffed. It doesn’t help that the average developer does not have the deep knowledge, hard-earned experience, nor the skill to work on such things -with those who do have the ability to do so usually being busy with core issues. To make matters worse, new devices seem to hit the market every single day, with each of them carrying a support burden that only serves to compound the unsupported driver problem.
A Few Prior Attempts
There have been numerous efforts levied at solving the device driver problem by various parties. A few that immediately come to mind are the Uniform Driver Interface (UDI), the Kernel Graphics Interface (KGI), and the Filesystem in Userspace for Devices (FUSD). Each of these projects had merits that could have proven to be successful long-term solutions (or ingredients to solutions), but they ultimately failed to obtain longevity.
An examination of each project exposes qualities that would actually benefit other operating system projects in addition to the OS actually targeted by each respective project. Highlights of UDI were portability across OSes, binary compatibility, an OS abstraction layer, encouragement of hardware vendor adoption as a core tenant of the project, and standardized APIs. KGI brought with it a clean kernel abstraction for graphics, provided a means for graphics functionality without needing the bulk of X11, improved security, and modular drivers. In a very real way, KGI paved the way for the eventual creation of the DRM & KMS technologies that are now used in the Linux kernel. Coming at the problem from userspace instead of inside of the kernel resulted in different benefits for FUSD. Focusing on userspace means that FUSD drivers are easier to develop than previous drivers, kernel modules don’t need to be developed, drivers can be isolated & hot reloaded, and can be prototyped substantially more easily.
However, most choices include tradeoffs. Each project also ended up facing large obstacles to adoption. UDI faced strong vendor resistance from almost all corners of the open source community and proprietary OS suppliers, included a high level of complexity involved in adoption, and inspired performance concerns do to its abstraction layers. KGI faced ridiculously strong resistance from X11 devs (who wanted to directly control hardware with their own drivers), flatout rejection from the Linux kernel devs, a lack of attraction of help to develop support for modern drivers, and eventually was out-performed by the newly developed DRM system. Anyone who’s been around long enough to remember the various monolithic kernel versus micro kernel debate could probably predict the issues with FUSD. Performance bottlenecks coincided with limited device support -especially concerning devices that had time-constrained data delivery (e.g. GPU & network cards). There was also the issue of security risks in the form of privilege escalation. Ultimately, newer development attempts in the form of UIO/VFIO eventually made FUSD obsolete.
All three projects were impressively promising and ambitious efforts, yet 2 were rendered obsolete with the other one being outright abandoned. In the wake of those outcomes, even with the advancements obtained since those projects’ hayday, we’re still in the same situation today as we were back then -open source device drivers are an absolute mess. What can we do about this? In my opinion, we should take a page from a commercial solution to this type of problem in regards to proprietary OSes.
A Potential Path Forward
Looking at these past attempts gives an interesting look at how different groups of people work towards solving similar problems. The majority of the work in this space has been geared towards solving the problem for Linux. Projects came and went, and Linux kept moving forward. At this point, Linux now has a level of corporate support that they did not have in the past. The device support problem is mostly a solved problem there, but what about every other open source operating system? Linux has been very successful at recruiting development support, but other projects have not been as successful for various reasons. So, what about the rest of the open source OS projects? What about the BSD communities? What are they to do? Well, a lot of time has gone by, so we now have some additional hindsight and knowledge of other technologies created by other organizations. For instance, Apple had to face the same problem. Consider the constraints that Apple has. For the most part, Apple doesn’t have as many developers working on drivers to ensure that devices work for their OS as there are making drivers for Windows or even Linux. Apple doesn’t have the ability to support every version of every new graphics card that hits the market. Apple doesn’t have unlimited time to spend on developing new drivers from the ground up. But what Apple DOES have is an interesting idea that they were able to implement in an extremely successful way -the IOKit. And yes, we all know that the IOKit has its roots in technology that was originally created at NeXT, Inc.
So, what exactly are we talking about here? What’re we looking at & what’re the takeaways? What we’re talking about is a tech stack that’s specifically designed to make the development, management, and operation of device drivers as simple as possible by leveraging OOP code written in an OOP language. We’re looking at a way to create drivers with common code heavily factored out of the drivers and placed in device “family” code that comes standard with MacOS X. The takeaways are that a better device driver architecture can be designed in a way that makes the task of keeping up with modern tech a bit easier to contend with. What should make the task even more manageable is for a few members of each of the BSD derivatives to actively participate in the development of this driver tech stack to ensure that it’s usable by all. And sure, plenty of people could bring up all types of potential problems with this approach. However, this approach has already proven itself to be successful and has already proven itself to be maintainable by a developer-constrained organization -which Apple definitely qualified for at the time in comparison to the number of developers who were writing device driver code for computers running the current version of MS Windows for that time period.
Of course, an effort like this can’t be started by simply porting the current driver architecture into an OOP language and calling it a day. While there’s a level of maturity to the code that’s already in place, there’s no denying the fact that there’re still limitations there that should be addressed in any new effort. So, any new effort should start by addressing lessons learned from past attempts. Any effort also needs to be written with the future in mind. Because of this, languages like assembly, C, & C++ should be left in the past. These drivers may be in use for decades. Two decades from now, it would absolutely be unreasonable to expect the developer pool to have enough developers knowledgeable in those older languages to be available to continue maintaining this effort. Additionally, development of scope should be limited to the most recent, relevant standards released for each category of devices. Outdated architectures should be pruned aggressively. The goal is to keep the BSD desktop in a consistently usable, stable state and to keep the developers from being needlessly overwhelmed maintaining code for severely irrelevant devices.
Conclusion
Ok, well that’s a lot to take in. With all of this being said, where do we go from here? Where can we go? Well, that depends on whether we’re ready to rethink how we approach this entire class of problems. We can keep doing what we’ve been doing—patching together partial ports, chasing Linux compatibility layers, and pretending that the lack of modern driver support isn’t a big deal. Or… we can try something new. Something deliberately designed to scale across projects, across teams, and across time. If Apple, with its limited internal resources compared to the broader industry, could pull off a maintainable and extensible driver stack using object-oriented principles, then there’s absolutely no reason the BSD ecosystem—or any open source OS community for that matter—can’t do the same. But it’s going to take discipline, cooperation, and a long-term mindset. We’ve got more than enough examples of what didn’t work. Maybe it’s finally time to build something that actually can.
