The Linux kernel has the ability to load and unload arbitrary sections of kernel code on demand. These loadable kernel modules run in privileged kernel mode and as a consequence have full access to all the hardware capabilities of the machine on which they run.
In theory, there is no restriction on what a kernel module is allowed to do; typically, a module might implement a device driver, a file system, or a networking protocol.
Kernel modules are convenient for several reasons. Linux's source code is free, so anybody wanting to write kernel code is able to compile a modified kernel and to reboot to load that new functionality; however, recompiling, relinking, and reloading the entire kernel is a cumbersome cycle to undertake when you are developing a new driver. If you use kernel modules, you do not have to make a new kernel to test a new driver—the driver can be compiled on its own and loaded into the already-running kernel. Of course, once a new driver is written, it can be distribttted as a module so that other users can benefit from it without having to rebuild their kernels. This latter point has another implication. Because it is covered by the GPL license, the Linux kernel cannot be released with proprietary components added to it, unless those new components are also released under the GPL and the source code for them is made available on demand. The kernel's module interface allows third parties to write and distribute, on their own terms, device drivers or file systems that could not be distributed under the GPL.
Kernel modules allow a Linux system to be set up with a standard, minimal kernel, without any extra device drivers built in. Any device drivers that the user needs can be either loaded explicitly by the system at startup or loaded automatically by the system on demand and unloaded when not in use. For example, a CD-ROM driver might be loaded when a CD is mounted and unloaded from memory when the CD is dismounted from the file system. The module support under Linux has three components:
1. The module management allows modules to be loaded into memory and to talk to the rest of the kernel.
2. The driver registration allows modules to tell the rest of the kernel that a new driver has become available.
3. A conflict-resolution mechanism allows different device drivers to reserve hardware resources and to protect those resources from accidental use by another driver
Loading a module requires more than just loading its binary contents into kernel memory. The system must also make sure that any references the module makes to kernel symbols or entry points are updated to point to the correct locations in the kernel's address space. Linux deals with this reference updating by splitting the job of module loading into two separate sections: the management of sections of module code in kernel memory and the handling of symbols that modules are allowed to reference.
Linux maintains an internal symbol table in the kernel. This symbol table does not contain the full set of symbols defined in the kernel during the latter's compilation; rather, a symbol must be exported explicitly by the kernel.
The set of exported symbols constitutes a well-defined interface by which a module can interact with the kernel. Although exporting symbols from a kernel function requires an explicit request by the programmer, no special effort is needed to import those symbols into a module. A module writer just uses the standard external linking of the C language: Any external symbols referenced by the module but not declared by it are simply marked as unresolved in the final module binary produced by the compiler. When a module is to be loaded into the kernel, a system utility first scans the module for these unresolved references. All symbols that still need to be resolved are looked up in the kernel's symbol table, and the correct addresses of those symbols in the currently running kernel are substituted into the module's code.
Only then is the module passed to the kernel for loading. If the system utility cannot resolve any references in the module by looking them up in the kernel's symbol table, then the module is rejected.
The loading of the module is performed in two stages. First, the moduleloader utility asks the kernel to reserve a continuous area of virtual kernel memory for the module. The kernel returns the address of the memory allocated, and the loader utility can use this address to relocate the module's machine code to the correct loading address. A second system call then passes the module, plus any symbol table that the new module wants to export, to the kernel. The module itself is now copied verbatim into the previously allocated space, and the kernel's symbol table is updated with the new symbols for possible use by other modules not yet loaded. The final module-management component is the module requestor.
The kernel defines a communication interface to which a module-management program can connect. With this connection established, the kernel will inform the management process whenever a process requests a device driver, file system, or network service that is not currently loaded and will give the manager the opportunity to load that service. The original service request will complete once the module is loaded. The manager process regularly queries the kernel to see whether a dynamically loaded module is still in use and unloads that module when it is no longer actively needed.
Once a module is loaded, it remains no more than an isolated region of memory until it lets the rest of the kernel know what new functionality it provides. The kernel maintains dynamic tables of all known drivers and provides a set of routines to allow drivers to be added to or removed from these tables at any time. The kernel makes sure that it calls a module's startup routine when that module is loaded and calls the module's cleanup routine before that module is unloaded: These routines are responsible for registering the module's functionality. A module may register many types of drivers and may register more than one driver if it wishes. For example, a device driver might want to register two separate mechanisms for accessing the device. Registration tables include the following items:
• Device drivers. These drivers include character devices (such as printers, terminals, and mice), block devices (including all disk drives), and network . interface devices. • File systems. The file system may be anything that implements Linux's virrual-file-system calling routines. It might implement a format for storing files on a disk, but it might equally well be a network file system, such as NFS, or a virtual file system whose contents are generated on demand, such as Linux's /proc file system. • Network protocols. A module may implement an entire networking protocol, such as IPX, or simply a new set of packet-filtering rules for a network firewr all. • Binary format. This format specifies a way of recognizing, and loading, a new type of executable file. In addition, a module can register a new set of entries in the sysctl and /proc ' tables, to allow that module to be configured dynamically
Commercial UNIX implementations are usually sold to run on a vendor's own hardware. One advantage of a single-supplier solution is that the software vendor has a good idea about what hardware configurations are possible. IBM PC hardware, however, comes in a vast number of configurations, with large numbers of possible drivers for devices such as network cards, SCSI controllers, and video display adapters. The problem of managing the hardware configuration becomes more severe when modular device drivers are supported, since the currently active set of devices becomes dynamically variable. Linux provides a central conflict-resolution mechanism to help arbitrate access to certain hardware resources. Its aims are as follows:
• To prevent modules from clashing over access to hardware resources
• To prevent autoprobes—device-driver probes that auto-detect device configuration—from interfering with existing device drivers j
• To resolve conflicts among multiple drivers trying to access the same j hardware—for example, as when both the parallel printer driver and the i: parallel-line IP (PLIP) network driver try to talk to the parallel printer port .,* To these ends, the kernel maintains lists of allocated hardware resources. E 1 The PC has a limited number of possible I/O ports (addresses in its hardware I" I/O address space), interrupt lines, and DMA channels; when any device driver I wants to access such a resource, it is expected to reserve the resource with I the kernel database first. This requirement incidentally allows the system ;i administrator to determine exactly which resources have been allocated by % which driver at any given point. :;
• A module is expected to use this mechanism to reserve in advance any f hardware resources that it expects to use. If the reservation is rejected because i the resource is not present or is already in use, then it is up to the module
The Linux System to decide how to proceed. It may fail its initialization and request thatnt be unloaded if it cannot continue, or it may carry on, using alternative hardware resources.