This chapter presents an overview of kernel modules by discussing the following topics:
Definition of kernel module
Purpose of a kernel module
The kernel module environment
Designing a kernel module
Writing a kernel module
A kernel module is a binary image containing 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 ending 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 book, 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 performing 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 like tasks in a single area and eliminating redundant code.
For example, assume you need to write a SCSI driver for disk and tape
peripheral devices.
You could write two
monolithic drivers-one
for each hardware device-but this would mean replicating a majority
of the code, while only a small amount would differ.
By writing a kernel
module containing common code, you eliminate this redundancy (see
).
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 would seamlessly
manage the expansion, while controller-specific code would be 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 would
maintain a consistent interface to the other kernel modules and make adding
the new driver easier.
1.1.2 Kernel Module Environment
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 .
A user-mode program that, in the context of this book, 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
, 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 in
can be thought of as the
background area of kernel space, loads, unloads, makes management requests,
and keeps track of the modules in kernel space.
User-mode code that is called by applications. Libraries contain routines that perform common functions used by many applications.
Kernel module code that is all-inclusive; supporting everything from user requests to processing interrupts from hardware.
A pseudodevice driver, such
as the
pty
terminal driver, structured like other drivers
but not operating on a bus and not controlling 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
The following are guidelines for you to consider when designing your 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 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 book is organized so that key tasks for writing a kernel module are logically grouped:
Section 1.2.1 describe 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 building and testing tasks that pertain to all kernel module writers.
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.
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.
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.
Using Callbacks
Kernel modules contain one or more callback 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.
Working in Kernel Mode
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.
Working in an SMP Enviroment
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
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 and Testing a Kernel Module
After you have written your kernel module, the next task is to build
the executable module (a
.mod
file) and test it.
Chapter 10
walks you through steps to build and test your
kernel module.