The first article about the drivers was really quite introductory, and I thought that it was impossible not to supplement it with a story about how the drivers of more modern devices are arranged.
To begin with, we introduce the definition of bus master: a device capable of being not only a slave, but also a master on a computer bus. That is, not only to respond to I / O transactions initiated by the processor, but also to initiate them independently — on their own initiative to “walk” into memory.
The history of such devices is rooted in the concept of DMA: as early as the time of the microprocessor progenitor, the 8080 microprocessor (KR5080IK80), it was understood that it would be good to unload the processor from the routine operation of drag-and-drop between devices in-in and memory.
The DMA controller (Direct Memory Access) was external to the I / O device subsystem that had to be explicitly programmed — set the type of operation (write to memory, read from memory, copy memory, memory), memory address (s), and so on. Actually, I’m completely unfair writing about it in the past tense - all of this quite exists now, for example, in microcontrollers.
')
Already in DMA mode, the driver’s operation looks essentially different - the driver is required not to perform I / O, but to prepare the settings for the device, activate it, wait for the interruption after I / O is completed, and check the success of the operation. Everything said in the previous article is also true for DMA devices, but in addition to the above, the driver must understand the scheme of interaction between the device and the DMA controller, and sometimes explicitly allocate and configure the controller: if in old devices the I / O port was fixed to the DMA controller , now in many cases it is possible to complete the routing or select the DMA channel from 2-4 options.
Separately, it should be noted that the initiation of the next I / O transaction itself can be automatic (DMA lupit as fast as possible), automatic with tempo adjustment (so as not to eat the entire bus bandwidth) or upon an event.
In this case, an event in the developed systems may be an interruption, simply a change in the state of the microcontroller's leg, or another event may be the source of the event. For example, a timer. This allows you to pair together the DAC, DMA engine and timer so that the next byte feed to the DAC will occur at the specified (timer) frequency. There are other options for the aggregation of devices, for example, the inclusion of one DMA channel at the end of another. Without attracting the attention of the processor.
It is also relevant to say that DMA controllers sometimes are able to explicitly match a pair of channels to ensure continuity of data flow at the end of one channel, the second one is triggered and an interrupt is generated, through which the processor loads the first channel again - this can be vital for the same DAC.
Back from the world of controllers in the "adult" cars. Most modern I / O subsystems are no longer based on external DMA, but have its counterpart right inside.
These are devices with the master bus mode, bus master.
It is easiest to imagine them as devices that have an in-built, personal and optimally arranged DMA controller.
Typically, such devices are controlled through a tree of descriptors in memory: the device has a special register in which the processor places the address of the structure in memory, which contains the task for the controller. Or, more often, an array or a list of structures with such tasks. The controller independently reads the tasks from the memory and executes them step by step. The task, as a rule, consists of the operation identifier, the address in the memory, where to get the data and the additional parameters necessary to perform the operation. For example: {write to disk, disk address, memory buffer address}. This is how modern controllers of everything are arranged: disk, USB, network interface.
In addition to the structure of the descriptors for such a device, more tools are needed for the exchange of events: the processor must be able to inform that it has changed or added descriptors, and the device — that has completed the I / O partially or completely. The second is executed, of course, through interrupts, and for the first, a register is often used (the doorbell is a doorbell), into which the processor “knocks” to draw the device’s attention to changes.
At the same time there is a danger of changing exactly what the device is processing now, which imposes additional restrictions on the structure of the driver.
Separately in this series are virtio devices. They appeared as a consequence of the victorious procession of hypervisors around the world. Traditionally, the hypervisor offered the guest OS some set of virtual devices that copied this or that popular physical device. Known network card or disk controller. But to emulate an “iron” device is hard, inconvenient, and dreary — often, you have to maintain properties that are completely unnecessary in the virtual world, while for the purposes of virtualization, the structure of a real iron device is usually not optimal.
This led the authors to design virtual devices that will never (never say © 007) be implemented in hardware and are needed solely for communication between the hypervisor and the guest OS. They are designed so that for a large number of devices of different types it is possible to implement a common uniform infrastructure, both in the core of the guest OS and in the hypervisor.
(
View implementation )
In essence, the virtio driver is a packet transport with requests and responses between the guest OS and the hypervisor. Package contents are specific to the type of driver and its mode. For example, for a network card, this is the address of the ethernet packet, and for a disk, the scatter-gather descriptor indicating the type of disk operation and the address on the disk.
In the virtio drivers, the kernel fills the package and asks the generic vitio driver to "transfer" it to the device. Now until the device “transmits” the packet back, it is impossible to touch it. Conversely, if the device is able to do input on the external initiative, it needs to transfer several empty (prepared for reading) packets — as data arrives (for example, incoming network messages), the packets will be filled and sent back to the kernel of the guest OS.
In addition, the virtio standard supports the ability for the kernel and device to agree on a mode of operation and supported functions in a standard way. For example, the virtio network driver may or may not be able to read and insert in the sent IP packets a checksum.
It is easy to see that the virtio standard describes a fairly typical generalized bus master device driver: we send a request to the device with an address in memory and I / O request parameters, the rest is asynchronous.
Against the background of the above, talking about DPC is no longer so relevant, but once a discussion has arisen in the comments, I will give a brief description.
In some operating systems (Phantom “sketched” it with NT, from where they sketched - I don’t know) there is full support for running code inside “light” threads - Deferred Procedure Call. This allows you to reduce the time the driver is in the interrupt: the interrupt handler only captures the event and, as a maximum, reads the status from the device - one register. The rest is done in the DPC, which is quickly activated and completes the job.
Frankly, there is not much point in this - it's easier to run its own high-priority thread in the driver and do input-output from it. However, there may be options. You can select a DPC priority group and always guarantee their priority is higher than that of the thread. It is possible to provide super-fast sheduling and transfer the processor directly to the output from the interrupt that this DPC requested, thus reducing latency.
Separately, we note that from the DPC can be a lot of what is not possible in the interrupt. What exactly - depends on the OS. In the Phantom inside the DPC everything is possible, including falling asleep for a month. Sin, but - it is possible. NT, EMNIP, nevertheless, somehow restricts the rights of the DPC (that is, these are not ordinary threads), but I don’t remember the details.
With this, I feel that I have fulfilled my duty towards the drivers. :)
Since May 1 you, albeit belatedly. :)