5. Linux Kernel’s Driver Management
< Android HAL >
Android. HAL (Hardware Abstraction Layer) Why? Linux kernel already includes a lot of driverset, why additional userspace device driver manager is needed?
Android can be configured by a lot different parts, compared to PC or server. Like lte modem, wifi chip, screen chip, etc. Linux’s mainline kernel cant manage all this many chips.
Its like alternative universal driver package. Variety of hardware config, but allow modular and consistent interface. (In Linux world, there are also Abstract Layers like HAL, like ALSA/PA or libinput or even FUSE is Abstract layer if you wanna say so…)
Its bridge between hardware driver and Android Framefork layer, and Android Framework driver provides universal interface. Android Apps can use those peripherals through standardized Android API (like Camera API or sensors, GPS..). Hardware vendors makes API driver? (can we say that’s server?) from their hardware to Android Manger class.
Linux Userspace Driver
“Userspace Driver.”
-
Different from non-mainline kernel drivers, these are done as 3rd party kernel modules or patches, not userspace drivers.
-
Userspace driver needs context-switching (unline kernel driver), so more overhead.
How exactly userspace drivers can access and use physical peripherals? Peripherals usually use “cpu port” in x86, and “memory map” in ARM. Unlike kernel that actually can access these without any restrictions, they somehow need to access to raw port or raw memory.
UIO (Userspace I/O)
-
Allows userspace apps to directly access hardware devices and handle interrupts.
-
Kernel module is paired with userspace component to do kernel jobs like things above. Its like proxy.
MMIO (Memory-Mapped I/O)
-
For memory-mapped register, userspace app can access device’s memory after mapped with mmap() syscall.
-
Q. Accessing arbitary raw memory addresses without MMU protection is restricted, isnt it?
-
A. mmap() allows userspace program to map specific portion of memory into its own address space.
or, map hardware register’s address into specific userspace virtual address.
Drivers and CPU Peripherals
CPU has its own preconfigured ports (or pins), e.g. PCI, USB, and I/O buses like SPI or I2C. Signal through this pins are handled by CPU as the part of SoC. If we take a look at CPU’s datasheet, we can see how pins are assigned for specific signals. CPU pins are assinged to RAM-related pins, JTAG, GPIO, PCIe, I2C, UART, SPI, and so on. Beside complex I/O like USB, PCIe, SATA that requires high datarate and strict signal timing, less complex I/O like UART or I2C can use GPIO pins for communication. GPIOs are versatile and can be programmed to communicate with various interfaces. This way of using software instead of dedicated hardware is called “bit banging”, and we can easily see this on like Arduino.
But there arent many interfaces that doesnt requires strict timing, only UART or basic I2C can be bit-banged. In most time, dedicated controller hardware is required. These hardware blocks can handle the timing and electric signals or even validation of data, thus ensures higher throughput and reliability.
CPU has limited amount of pins, and we need to connect tremendous amount of devices. External hardware controllers and buses are required to expand I/O. These controllers can often interface with many devices on the same bus (like multiple SPI or I2C devices) and serialize the communications.
Serialization is the key of efficient communication. CPU technology is eveolved, and we can use very high speed buses. With these high-speed buses serial communication has advantage over paralell communication, which was primarily used when we only had low-speed buses.
Well, there was northbridge and southbridge long CPU ago, CPU needed additional chipset for all high speed interface, like RAM or PCIe. Then northbridge is directly connected to CPU via “Front side bus”. {{ }} .
Currently, just those bridges are integrated into CPU as SoC] or just one chipsets. Those chipsets connects to CPU as PCIe.
During the boot process, the OS will initialize MMU, but in early stage of booting, the CPU may operate in a mode where the MMU in not yey enabled or is configured to provide a direct mapping, so that kernel can to permissive tasks. Once OS is loaded, is first sets up MMU with kernel’s own memory mapping setup, and also necessary permissions among address spaces.
In case of MMIO, OS will configure MMU to create direct mapping between requesting process’s VA space and device’s physical address that its register mapped into. Also disabling CPU caching is done for this address range.
So, How does OS configure MMU?
-
Setting up page tables: The OS creates and populates page tables that define the mapping between virtual and physical addresses.
-
Configuring control registers: The OS sets specific CPU control registers to enable the MMU and define its behavior.
-
Flushing TLB: After making changes, the OS flushes the Translation Lookaside Buffer (TLB) to ensure the new mappings take effect.
-
Setting up memory attributes: The OS configures memory attributes for different regions, such as cacheability, executability, and access permissions.
-
Handling exceptions: The OS sets up handlers for page faults and other memory-related exceptions.
- libusb?
userspace USB comm without kernel things, FUSE allows userspace filesystem. Interact directly with hardware or implement file systems without requiring kernel-level drivers.
- ioctl calls?
Communicating with device drivers? Allows user-space programs -> device-specific command to drivers? query device status? (anyway which isnt read/write)
Linux’s driver problem
- Peripherals are growing exponentially, even Embedded controller itself is also many. If Linux kernel supports them all, it will be so big, even with kernel modules. Large scale makes system unstable. With this in mind, I think switching drivers from kernel-space-large-codebase-driver to userspace modular and seperate driver managing is better. Also Linux kernel’s driver isnt equally supported in mainline. They hates merging propriety drivers, even though it is important to include it for user experience.
- Linux’s Monolithic Kernelspace Driver managing .. Security, Performance, Reusability, it is Modular so not a big deal, Consistency, Reliability, ..
- Drivers for standard buses like USB, PCI, I2C, SPI, … low-level protocol wrappers. But device drivers are not standardized. Even if they uses same USB protocol, each embedded controllers (specific USB host controller or I2C controller chip) needs independant drivers.
- High-level device drivers that uses standard protocol.Like touchscreen, usb webcam, … Those devices sends data over protocol. Protocol part of driver is done by generic/protocol driver and device-specific drivers are built on top of generic/protocol drivers. Like, parsing data structure on top of passed data through USB or I2C into x-pos and y-pos.
- Vendor-specific drivers usually do: “device initialize / power managing / parsing raw data to kernel subsystem / device config like volume, sensitivity..”
- high-level behavior and data structures that the device uses over the communication protocol
- DKMS