General question about "drivers"

I’ve been doing a bit of research as I’m unfamiliar with some of thus stuff. It seems that certain peripherals are actually made available via a “driver” which is (if I understand correctly) loaded dynamically into the OS kernel space, so it can obviously access kernel resources and execute (when needed) in an elevated kernel mode.

What isn’t very clear is the motivation for these and for which peripherals they are deemed necessary.

The GPIO ports for example are accessible via their registers, granted these do not need to exhibit complex behavior so they do not need any such driver.

Given that one can access device registers, I have the question - why is a Linux driver needed? Could the operations performed by SPI for example not be implemented outside of any driver, just write code that manipulates the necessary registers.

I’ve written SPI code in C on STM32 MCU devices and although there’s some fiddling around it was not overly demanding.

Why do we even need Linux to get involved with this kind if IO? If one can write code that accesses the necessary hardware registers (perhaps even purely managed code) then one could - in principle - create an implementation that does not rely on Linux or kernel drivers.

How is the decision made to decide “we can do this ourselves accessing registers” and “we can’t do this ourselves, we must rely on Linux”?

Thoughts?

Endpoint’s runtime (linux) is a multi-process operating system. Separate processes can (and are) running at any given time. Any/all of them could reach out and fiddle the bits directly, and with no coordination between them, that would result in access collisions and instability. You can’t have one process choose a SPI alternate function and another process choose a UART AF for the same pin. You can’t have one process set a GPIO or SPI CS pin high and another set it low during the same SPI transaction.

Drivers are the arbiters between the hardware and the multi-process world. They run in a privileged ring and are stateful with respect to what application requests are pending across all threads and processes. They can serialize those requests or deny access based on whatever is safe/legitimate for that device/bus/etc.

Now, the fact that you can safely fiddle the bits from your dotnet program is because you are safe in the knowledge that you are the only process trying to do so at any given moment because you have excluded the possibility of other unknown applications or users creating conflicting operations. You are author of the app code, and administrator of the process mix.

But if you fiddle hardware directly, you have no guarantee that a firmware change to the RTOS code or new code from GHI won’t scupper your code in the future. However, if you act through a driver, you have a stronger guarantee that you and even GHI’s code, will be playing by the same set of rules - the driver’s ioctl contract.

So, the basic rule (IMHO) is that if there’s a driver, use it. It’s there to provide certainty and stability. If there is no driver, then access the hardware directly, but recognize that stable behavior now relies only on your application-layer behavior and your control of the process mix as it’s guarantor.

1 Like

:nerd_face:

Dude asked a ‘why’ question, and professor-mode got activated. Can’t help it. It’s been a lifelong struggle.

2 Likes

Drivers also provide an abstraction layer to the hardware.

Endpoint does not have any type of memory protection activate. This allows direct access to hardware. As Martin said, there is no guarantee that this access will continue to be available.

1 Like

In the spirit of multi-threading, multi-core development the safest bet is to work through drivers. Not to mention the 3rd M4 core factors into direct writes to registers.

1 Like

Thanks Martin.

Yes that’s more or less what I gathering here, the OS is a means of policing access to the peripherals, preventing chaos basically. If such policing was taken care of by some other software component though, that problem could (at least in principle) be solved without the OS needing to do that.

What I’m seeing as I dig into all this, is a bit of an unclear landscape, the design of these abstractions seems to be non-standardized, what I mean is if we look at the WDM in Windows there is a very formal and solid standard pattern that a driver must conform too, note (from that article I linked to)

There is no formal framework for Linux device drivers, but Linux kernel includes numerous subsystems that provide common services like driver registration.

Creating some new or improved driver here, say for SPI (for no particular reason) forces us to dive into Linux driver development and either take some existing driver from some place and extend it or create a new one from scratch, this could be a lot of work and if we are for any reason dissatisfied with some existing abstraction we will be unlikely to want to do much about it and just make do.

The past few weeks when I’ve had time to explore, I’ve seen that we have these Linux drivers like spidev for SPI and also stuff like Libgpiod as well, I’m still far from clear on exactly how these all play together too.

I’m wondering how one could design “drivers” outside of Linux, away from the OS.

If one commits to a “Let Linux do it” approach then it seems to me that we are somewhat at the mercy of whatever exists with whatever abstractions it offers, for example as you will know spidev offers no support for asynchronous (nor it seems, full duplex) operation.

Under the hood of course, in any OS I’ve ever worked on, all IO is ultimately asynchronous, not synchronous. A synchronous interface is often exposed on top of the asynchronous one because it’s all that most users might need (this was the case some years ago anyway).

Unlike traditional PCs running Windows and Linux etc, these ST devices (for example) do have a very uniform devices model, they expose very well documented IO registers and these are very easy to access by code without any nececsity of some intervening OS, so its easier to get at the hardware than it typically is on a PC.

Some of the work I’ve been doing the past couple weeks too, is suggesting that C# has now reached the stage where interacting with such hardware is now much easier than in the old days and the performance of this is no longer a major cost.

The ST32MP1X devices though are far from simple, they are pretty sophisticated and I don’t want to imply they are not!

I should add, that I know that I’m looking at all this very idealistically, I do not work professionally on these kinds of systems but I do have considerable experience in low level software and OS internals, so I’m probably just dumb enough to try ridiculous ideas!

From what I’ve discovered Linux prevents any access to the physical addresses used by registers and the standard way to handle that is to invoke the Linux mmap family of functions. These let us define an alternate (and accessible) address for any hardware register.