banner
ShuWa

ShuWa

是进亦忧,退亦忧。然则何时而乐耶?
twitter

Device Management

Device Controller#

To shield the differences between devices, each device has a component called Device Controller, such as a hard disk controller for hard disks, a video controller for monitors, etc.

There are three types of registers in the controller, namely Status Register, Command Register, and Data Register, as shown in the figure below:

image

The functions of these three registers are as follows:

  • Data Register: The CPU writes the data to be transmitted to the I/O device, such as sending an "H" character to the corresponding I/O device if the content to be printed is "Hello".
  • Command Register: The CPU sends a command to the I/O device to perform input/output operations. After the task is completed, the status in the status register is marked as completed.
  • Status Register: Its purpose is to inform the CPU whether it is currently working or has already completed the work. If it is in a working state, any data or command sent by the CPU is useless until the previous work is completed and the status register is marked as completed. Only then can the CPU send the next character and command.

The CPU controls the device by reading and writing the registers in the device controller, which is much more convenient and standardized than the CPU directly controlling the input/output devices.

In addition, input/output devices can be divided into two categories: Block Devices and Character Devices.

  • Block Devices: They store data in fixed-size blocks, each with its own address. Hard disks and USBs are common block devices.
  • Character Devices: They send or receive a stream of characters. Character devices are not addressable and do not have any seek operations. Mice are common character devices.

Block devices usually transfer a large amount of data, so the controller sets up a readable and writable data buffer.

  • When the CPU writes data to the controller's buffer, the data will only be sent to the device when the buffer has accumulated a certain amount.
  • When the CPU reads data from the controller's buffer, it needs to wait until the buffer has accumulated a certain amount before copying it to memory.

This is done to reduce frequent operations on the device.

So how does the CPU communicate with the control registers and data buffers of the device? There are two methods:

  • Port I/O: Each control register is assigned an I/O port, and these registers can be operated using special assembly instructions, such as in/out-like instructions.
  • Memory-mapped I/O: All control registers are mapped to the memory space, so that the data buffer can be read and written like memory.

I/O Control Modes#

Using interrupts for frequent read and write operations on disks is not friendly because it can easily interrupt the CPU and occupy a lot of CPU time. The solution to this problem is to use DMA (Direct Memory Access) to allow devices to complete I/O data transfer to memory without the involvement of the CPU. To implement DMA, hardware support from a "DMA Controller" is required.

image

Device Driver#

Although the device controller shields many details of the device, the usage patterns of registers and buffers for each device controller are different. Therefore, to shield the differences of the "Device Controller", a Device Driver is introduced.

The "Device Controller" does not belong to the operating system, it is hardware. The "Device Driver" is part of the operating system, and the kernel code of the operating system can use the interface of the "Device Driver" like calling local code. The "Device Driver" is the code for the "Device Controller". It can operate the "Device Controller" after issuing instructions to manipulate the "Device Controller".

Although different device controllers have different functions, the "Device Driver" provides a unified interface to the operating system. This allows different device drivers to be integrated into the operating system in the same way.

As mentioned earlier, there are many things about interrupts. When a device completes a task, it sends an interrupt to notify the operating system. The operating system needs a place to handle this interrupt, which is in the "Device Driver". It will promptly respond to the interrupt request sent by the controller and call the corresponding interrupt handler based on the type of the interrupt to process it.

image

Generic Block Layer#

For block devices, in order to minimize the impact of differences between different block devices, Linux uses a unified Generic Block Layer to manage different block devices.

The Generic Block Layer is an abstraction layer between the file system and the disk driver. It has two main functions:

  • The first function is to provide a standard interface for file systems and applications to access block devices, and to abstract various different disk devices into unified block devices. At the kernel level, it provides a framework to manage the drivers for these devices.
  • The second function is to queue I/O requests from file systems and applications, and then reorganize the queue, merge requests, and perform I/O scheduling. The main purpose is to improve the efficiency of disk read and write operations.

Linux supports 5 I/O scheduling algorithms in memory:

  • No scheduling algorithm: It does not process file system and application I/O, which is commonly used in virtual machine I/O. In this case, the disk I/O scheduling algorithm is handled by the physical machine system.
  • First-In-First-Out (FIFO) scheduling algorithm
  • Completely Fair Scheduling (CFS) algorithm: It maintains an I/O scheduling queue for each process and evenly distributes I/O requests for each process based on time slices.
  • Priority scheduling
  • Deadline scheduling algorithm: It creates separate I/O queues for read and write requests, which can improve the throughput of mechanical disks and ensure that requests with deadlines are processed first. It is suitable for scenarios with high I/O pressure, such as databases.

Storage System I/O Software Layers#

The I/O of the Linux storage system can be divided into three layers from top to bottom: the file system layer, the generic block layer, and the device layer. The hierarchical relationship of these three layers is shown in the following figure:

image

The functions of these three layers are as follows:

  • The file system layer includes the virtual file system and the specific implementations of other file systems. It provides a standard file access interface for applications and file systems, and uses the generic block layer to store and manage disk data.
  • The generic block layer includes the I/O queue and I/O scheduler for block devices. It queues I/O requests from the file system and selects an I/O to be sent to the device layer through the I/O scheduler.
  • The device layer includes hardware devices, device controllers, and device drivers. It is responsible for the physical I/O operations of the devices.

With the file system interface, devices can be operated like special files in Linux, not only through file system commands but also through application programs using read and write functions to operate devices as if they were reading and writing files. Therefore, devices in Linux are just special files.

However, in addition to read and write operations, it is also necessary to check the specific functions and attributes of the device. Therefore, the ioctl interface is needed, which stands for Input/Output Control, and it is a general interface for configuring and modifying specific device properties.

In addition, I/O is the slowest part of the entire system, so Linux provides many caching mechanisms to improve I/O efficiency.

  • To improve file access efficiency, various caching mechanisms such as page cache, inode cache, and directory entry cache are used to reduce direct calls to block devices.
  • To improve the access efficiency of block devices, a buffer cache is used to cache the data of block devices.

What Happens When a Letter is Typed on the Keyboard?#

image
The memory interface inside the CPU communicates directly with the system bus, and then the system bus connects to an I/O bridge. On the other side of the I/O bridge, it connects to the memory bus, enabling communication between the CPU and memory. On the other side, it connects to an I/O bus for connecting I/O devices such as keyboards and displays.

When a user enters a keyboard character, the keyboard controller generates a scan code and stores it in the register of the keyboard controller. Then, the keyboard controller sends an interrupt request to the CPU via the bus.

After receiving the interrupt request, the operating system will save the CPU context of the interrupted process and then call the interrupt handler for the keyboard.

The interrupt handler for the keyboard is registered when the keyboard driver is initialized. The purpose of the interrupt handler function for the keyboard is to read the scan code from the buffer of the keyboard controller and find the character entered by the user based on the scan code. If the entered character is a display character, the scan code will be translated into the corresponding ASCII code of the display character. For example, if the user enters the letter "A" on the keyboard, which is a display character, the scan code will be translated into the ASCII code of the letter "A".

After obtaining the ASCII code of the display character, it will be placed in the "read buffer queue". Next, the character will be displayed on the screen. The driver of the display device will periodically read data from the "read buffer queue" and write the data one by one into the data buffer of the display device's controller. Finally, these data will be displayed on the screen.

After displaying the result, the interrupt handler will restore the context of the interrupted process.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.