What does the computer do when an I/O operation needs to be done during the process? Does the message that we need to do some I/O operation directly reaches the device controller or device driver? What does the operating system have to do with this?
-
$\begingroup$ A user-process requests from the operating system to do the i/o operation, which in turn sends the required signals to the correct device driver, which talks directly with the device itself. In short, its like so: user->OS->device driver->device $\endgroup$– nir shaharCommented Mar 11, 2022 at 7:25
-
$\begingroup$ This is a very broad question, as not two devices are handled the same way. But I/O operations are absolutely handled by the OS, usually in priviledged modes (so that you can't bypass the OS). When there is a controller, the device driver prepares the message and context data in a suitable way and sends a request to the controller; then it enters a waiting mode, until the device sends an interrupt to signal the end of the transaction. The "physical" transfer of information to the device is performed by the controller. $\endgroup$– user16034Commented Mar 11, 2022 at 13:28
1 Answer
I don't know how it is implemented in hardware but in software you have mostly MMIO PCI device registers. PCI devices all have a conventional PCI configuration space. The configuration space also have BAR registers that point to other portions of the configuration space which are specific to the device. Each device have a specification document that specifies how the device specific portion of the config space works.
PCI devices work with memory mapped IO (MMIO). The kernel writes to some portion of the virtual address space that is not cached to write to the registers of the device. This allows to configure the device.
In general, the kernel has the higher half of the virtual address space reserved for its code and data segment (and other things). The kernel must reside within 2GB due to limitations in RIP-relative machine code where the offset from code must be a maximum of 2GB. This is often easily done because the kernel doesn't require this much space. The rest of the higher half of the virtual address space can be accessed with 64 bits pointers This portion of the address space is marked as global in the page tables to avoid a TLB flush on context switch (when the page table base pointer is changed).
The kernel is invoked from user mode by using syscall
which has a specific binary encoding specified in the manual (the software specification) of the processor. This instruction makes the processor jump to an address specified in a register that is specified by the kernel at boot.
If you write C/C++ code, the code makes calls in the lib/libc++ library which is a shared object that implements the C/C++ standard library. The standard library implementation is loaded alongside your executable and the symbols of the library are resolved before runtime by the dynamic loader.
Most operating-systems implement some form of virtual-filesystem where every device is presented to the upper layer of the OS as a file. For example, Linux has several categories of device drivers and a more broad category which is character devices. The character devices are general drivers that are implemented as virtual files that you can open to do file operations on them. The driver is thus free to do anything in the file operation implementation.
For example, if you use the write syscall on a device, it could write to the PCI registers of the device to trigger some operations. PCI devices are DMA so they directly read/write RAM with a separate bus. Now this must be managed by the OS by making sure the user mode buffer is not cached or swapped to the hard-disk. It comes with a lot of complexities.
The virtual-filesystem thus makes the driver model modular because it allows to add generic drivers in the kernel while it is running. You can also store the module in a specific directory to make sure it is loaded at boot.