This chapter presents an overview of kernel modules by discussing the following topics:
Definition of kernel module (Section 1.1)
Purpose of a kernel module (Section 1.1.1)
The kernel module environment (Section 1.1.2)
Designing a kernel module (Section 1.1.3)
Writing a kernel module (Section 1.2)
A kernel module is a binary image that contains code and data structures that runs in the UNIX kernel. It has the following characteristics:
Is statically loaded as part of
/vmunix
or dynamically loaded into memory
Runs in kernel mode
Has a file name that ends with the extension
.mod
Contains a well-defined routine that executes first to initialize the module
May be a device driver when it performs any one of these additional tasks:
Handles interrupts from hardware devices
Accepts I/O requests from applications
The kernel contains many modules, some of which are device drivers. In this manual, a kernel module is defined more broadly than a device driver because it can be used to perform a variety of functions, including:
Management functions
Common functions shared by other modules
1.1.1 Purpose of a Kernel Module
The kernel consists of a set of kernel modules that interact with each other, each of which performs a specific function. Some kernel modules perform software functions exclusively, while others (such as device drivers) control the operation of system hardware components.
A purpose for writing a kernel module is to provide a middle layer of code, or common code, thus increasing the efficiency of your system by combining similar tasks in a single area and eliminating redundant code.
For example, assume that you need to write a SCSI driver for disk and
tape peripheral devices.
You can write two
monolithic drivers- one for each hardware device-but
this means replicating a majority of the code, while only a small amount differs.
By writing a kernel that module contains common code, you eliminate this
redundancy (see
Figure 1-1).
One class
driver might handle SCSI tapes and another handle SCSI disks.
Both call
the kernel module, which sends the I/O request to a variety of port drivers.
The port drivers send requests to the SCSI controller.
As you add more disk
or tape drives to your system, the kernel module seamlessly manages the expansion,
while controller-specific code is confined to the new port drivers.
Similarly,
you can add a different SCSI device (for example, a scanner) by writing a
new class driver.
The kernel module maintains a consistent interface to the
other kernel modules and make adding the new driver easier.
1.1.2 Kernel Module Environment
Figure 1-1
shows a kernel module
in relationship to other modules in the kernel.
As a binary image, a kernel
module can be loaded statically as part of
/vmunix
or dynamically
loaded into memory.
In this example, the kernel module is part of a driver
subsystem.
Figure 1-1: Kernel Module Environment
The following list describes the main components in Figure 1-1.
A user-mode program that, in the context of this manual, makes various requests to the kernel modules. If a kernel module is part of a device driver, these requests typically perform I/O operations to hardware components. Another term for application is utility.
A hardware component that connects multiple buses and controllers to the system.
The class/port driver comprises two drivers. The class driver supports user interfaces while the port driver supports the hardware and handles interrupts. The driver model is always made of more than one module and it can have multiple class drivers, multiple port drivers, and some common code in a middle layer. The structure of this driver eliminates code duplication.
A hardware component that performs a specific function, such as communicate on the network or control the graphics monitor.
A hardware component that is connected to a controller.
A kernel module that supports one or more hardware components. There are two driver models: the monolithic driver model and the class/port driver model.
A signal from a hardware component that eventually causes the interrupt handler in the appropriate driver to be called.
A
.mod
file residing
in the kernel that executes common code.
In
Figure 1-1,
the kernel module is part of a device driver.
Activities that happen within the
UNIX kernel.
Modules may be statically loaded as part of
/vmunix
or dynamically loaded as needed.
The
module framework, which
Figure 1-1
depicts as the background area of kernel space, loads modules, unloads modules,
makes management requests, and keeps track of the modules in kernel space.
User-mode code applications call. Libraries contain routines that perform common functions that many applications use.
Kernel module code that is all-inclusive; supporting everything from user requests to processing interrupts from hardware.
A driver, such as the
pty
terminal driver, structured like other drivers but does not
operate on a bus and does not control hardware.
A pseudodevice driver does
not register itself in the hardware topology (system configuration tree).
Instead, it relies on the device driver method of the
cfgmgr
framework to create the associated device special files.
A data structure in the kernel where the block and character I/O interface entry points are stored.
Routines in the kernel that can be called from user mode (applications and libraries).
User application level or command-line interface to the operating system.
1.1.3 Designing a Kernel Module
Consider the following guidelines when you design a kernel module:
A kernel module is best written as a
single binary image
that can be statically loaded as part
of
/vmunix
or dynamically loaded into memory.
When you write your kernel module, it is important to design
your code correctly with regard to
dispatch points
along the
boot timeline.
These are points along the boot path (timeline)
that are reached as the operating system boots.
When a dispatch point is reached,
certain things are configured and made available.
As a single binary image,
your kernel module can be statically loaded as part of
/vmunix
or dynamically loaded into memory; therefore, any callbacks that you register
must reflect the proper order of dispatch along the boot timeline (see
Chapter 2).
If you support dynamically loaded kernel modules, plan to write features that support dynamic unloading as well, for these reasons:
Unloading a module will free up resources.
Dynamic unloading allows you to replace an old version of a kernel module with a new version without rebooting.
1.2 Writing a Kernel Module -- Key Tasks
This section is organized so that key tasks for writing a kernel module are logically grouped:
Section 1.2.1 describe required tasks that all kernel module writers need to perform to develop a kernel module.
Section 1.2.2 describes optional tasks for writers whose modules run in an SMP environment or use kernel threads.
Section 1.2.3 describes how to build a kernel module.
All kernel module writers need to understand module initialization,
creating the module attribute table, using callbacks, and working in kernel
mode.
The following sections describe these tasks.
1.2.1.1 Initializing a Kernel Module
Kernel module
initialization
occurs in both
static
and
dynamic
mode.
Kernel module writers must understand the
concept of a single binary image, the build-load-initialize sequence, and
how to use the
configure
routine to perform initialization
tasks to add a kernel module (make it known to the kernel) or to remove it.
Chapter 2
describes these concepts and the required
tasks for coding your kernel module to initialize properly.
It also describes
how to unload dynamically loaded modules.
1.2.1.2 Creating the Attribute Table
All kernel modules must contain an
attribute table.
Chapter 3
describes
a variety of tasks you can perform on the module attribute table to retrieve
data from the table and set data in the table.
1.2.1.3 Using Callbacks
Kernel modules contain one or morecallback routines
that perform different aspects of initialization
along the boot timeline.
Coding callback routines in a kernel module is a
key task for creating a kernel module that may function as a single binary
image.
Chapter 4
describes the rules for using callbacks
in a kernel module.
It discusses callbacks in relation to dispatch points
along the boot timeline, and how the kernel calls the kernel module's
callback routine.
1.2.1.4 Working in Kernel Modules
You can perform many tasks in kernel mode. Chapter 5 describes how to:
Work with string routines
Use data copying routines
Use kernel-related routines
Work with system time
Use kernel threads
Use locks
If your kernel module executes in a
symmetric multiprocessing
(SMP) environment or uses kernel
threads, you must perform additional tasks, as described in the following
sections.
1.2.2.1 Working in an SMP Environment
Selecting a locking methodology and coding the correct type of lock in your kernel module are key tasks for writing kernel modules that execute in an SMP environment. Chapter 6 through Chapter 8 describe how to:
Choose a locking methodology
Use simple lock routines
Use complex lock routines
1.2.2.2 Working with Kernel Threads
Chapter 9 describes the key concepts and tasks for developing kernel modules that use kernel threads. These include:
Advantages of using kernel threads
Kernel threads operations
Kernel threads data structures
Creating, starting, blocking, unblocking, and terminating thread processes
1.2.3 Building a Kernel Module
After you have written your kernel module, the next task is to build
the executable module (a
.mod
file).
Chapter 10
walks you through steps to build your kernel module.