Skip to content
Digital Rhyme

Build a Simple Linux Kernel Driver

A compact guide to the shape of a basic Linux kernel module: the important functions, the build flow, how to load it, how to test it, and how to remove it cleanly.

Small Linux development board beside a laptop and simple driver workflow sketches

What You Are Building

The simplest useful kernel driver is often a loadable kernel module, built as a .ko file. The example here creates a tiny character device called /dev/hello_kmod. When userspace reads from it, the driver returns a short message.

Kernel code runs with high privilege. Build and test examples on a VM, lab machine, or disposable development system before using them anywhere important.

Main Functions

A small character-device module has a few core pieces:

  • hello_init: runs when the module is loaded with insmod. It registers the character device and creates /dev/hello_kmod.
  • hello_exit: runs when the module is unloaded with rmmod. It destroys the device and unregisters the major number.
  • hello_open: runs when a process opens the device file.
  • hello_read: copies data from kernel memory to userspace with copy_to_user.
  • hello_release: runs when the process closes the device file.
  • struct file_operations: connects userspace file actions to your driver callbacks.
  • module_init and module_exit: tell the kernel which functions are the module entry and exit points.

Procedure

  1. Install the kernel headers/build files for your running kernel.
  2. Write a module source file, usually something like hello_kmod.c.
  3. Write a kernel-module Makefile using obj-m.
  4. Build with the kernel build system, not with a plain gcc hello_kmod.c.
  5. Load the module with sudo insmod hello_kmod.ko.
  6. Check logs with dmesg or journalctl -k.
  7. Test the device from userspace.
  8. Unload it with sudo rmmod hello_kmod.

Sample Driver C File

The full file is available at examples/simple_kernel_driver/hello_kmod.c. This is the core shape:

// SPDX-License-Identifier: GPL-2.0
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "hello_kmod"
#define CLASS_NAME "hello_class"

static int major_number;
static struct class *hello_class;
static struct device *hello_device;
static const char message[] = "hello from a tiny kernel driver\n";

static ssize_t hello_read(struct file *file, char __user *buffer,
			  size_t length, loff_t *offset)
{
	size_t message_len = sizeof(message) - 1;
	size_t bytes_to_copy;

	if (*offset >= message_len)
		return 0;

	bytes_to_copy = min(length, message_len - (size_t)*offset);

	if (copy_to_user(buffer, message + *offset, bytes_to_copy))
		return -EFAULT;

	*offset += bytes_to_copy;
	return bytes_to_copy;
}

static const struct file_operations hello_fops = {
	.owner = THIS_MODULE,
	.open = hello_open,
	.read = hello_read,
	.release = hello_release,
};

module_init(hello_init);
module_exit(hello_exit);

The real file includes the complete open, release, init, and exit implementations.

Sample Makefile

Yes, this is the normal/recommended way to build an out-of-tree Linux kernel module. You let the kernel build system compile the module because it knows the correct flags, generated headers, symbol versions, and module metadata for the running kernel.

obj-m += hello_kmod.o

KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

The full file is available at examples/simple_kernel_driver/Makefile.

How To Use This Makefile

On Ubuntu/Debian, install the headers for the kernel you are currently running:

sudo apt update
sudo apt install build-essential linux-headers-$(uname -r)

Then build the module from the directory containing hello_kmod.c and Makefile:

cd examples/simple_kernel_driver
make

The important output is:

hello_kmod.ko

That .ko file is the loadable kernel module. The temporary files such as .mod, .o, Module.symvers, and modules.order are normal kernel-build artifacts.

Load And Test

Load the module:

sudo insmod hello_kmod.ko

Confirm it loaded:

lsmod | grep hello_kmod
dmesg | tail

Read from the device:

cat /dev/hello_kmod

You should see:

hello from a tiny kernel driver

Unload And Clean

Unload the module:

sudo rmmod hello_kmod

Remove build artifacts:

make clean
If rmmod says the module is busy, close any shell or program that still has /dev/hello_kmod open, then try again.