All the drivers in the Linux running in the same context (address space of the kernel-space), or each in a different (similar to how the different processes work in a different address spaces in user-space)?
Often, device drivers provide that gateway. Device drivers take on a special role in the Linux kernel. They are distinct “black boxes” that make a particular piece of hardware respond to a well-defined internal programming interface; they hide completely the details of how the device works.
There are many different device drivers in the Linux kernel (that is one of Linux's strengths) but they all share some common attributes: kernel code. Device drivers are part of the kernel and, like other code within the kernel, if they go wrong they can seriously damage the system.
The driver context determines which kernel routines the driver is permitted to call. There are four contexts in which driver code executes: User context – A driver entry point has user context if it was directly invoked because of a user thread.
The Linux kernel supports two main types of USB drivers: drivers on a host system and drivers on a device. The USB drivers for a host system control the USB devices that are plugged into it, from the host's point of view (a common USB host is a desktop computer.)
In x86-Linux, 32 bits, all drivers run in so called kernel mode (sometimes called Ring 0 mode because of the way Intel organized its CPU protection scheme).
When a driver is called by a process (say, you issue for example an read()
system call to a device driver), there's a function inside the driver that gets executed. That function is said to be executed in that process's context.
What this means is that the driver function executes within the memory map of the calling process. This implies that the driver function can access not only its own variables and structures stored in the kernel reserved addresses (virtual address 0xC0000000 and up) but can access variables and code of the user calling process. This allows functions like copy_to_user()
or copy_from_user()
to be able to interchange information with the user calling process.
Recall that the memory map of any process in Linux has two parts: one big part of a maximum of 3GB of memory available to the user process. This memory is private for that process. Another part of 1GB is for the kernel. This part is shared among all user processes' memory maps. The code, stack and global variables of a driver resides within this 1GB space.
There's another context: the interrupt context. A Linux driver can install a handler for a hardware interrupt. When this interrupt is triggered, the handler is executed, but this time, it will execute in the context of whatever process was being executed at that moment (i.e. the handler has not been called from an user process)
A typical driver is then a collection of functions, the majority of them are executed upon a request from an user process making a system call, so the most of the time, a driver is being executed (an instance of it actually) in the context of a particular user process (but unlike the code in the user process, the driver executes with all priviledges). Parts of the driver may be called asyncronously by other kernel functions, so they could be executing in another context, not related with the one belonging to the process that is using the driver.
Also remember that more than one user process could be using the driver, so each process executes the same code under its own context. A driver should be written so it can be reentered, so avoiding side effects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With