linux-kernel-modules
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLinux Kernel Modules
Linux内核模块
Purpose
用途
Guide agents through writing loadable Linux kernel modules (LKMs): the Kbuild build system, module parameters, /proc and sysfs interfaces, character device implementation, kernel debugging with KGDB and , and module signing for Secure Boot.
ftrace引导开发者完成可加载Linux内核模块(LKM)的编写工作:包括Kbuild构建系统、模块参数、/proc和sysfs接口、字符设备实现、使用KGDB和进行内核调试,以及Secure Boot下的模块签名。
ftraceTriggers
触发场景
- "How do I write a Linux kernel module?"
- "How do I add parameters to my kernel module?"
- "How do I create a /proc or sysfs entry?"
- "How do I implement a character device driver?"
- "How do I debug a kernel module with KGDB?"
- "How do I sign a kernel module for Secure Boot?"
- "如何编写Linux内核模块?"
- "如何为内核模块添加参数?"
- "如何创建/proc或sysfs条目?"
- "如何实现字符设备驱动?"
- "如何使用KGDB调试内核模块?"
- "如何为Secure Boot签名内核模块?"
Workflow
操作流程
1. Minimal kernel module
1. 最小化内核模块
c
// hello.c — minimal loadable kernel module
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Minimal hello world module");
MODULE_VERSION("1.0");
static int __init hello_init(void)
{
printk(KERN_INFO "hello: module loaded\n");
return 0; // non-zero = load failure
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "hello: module unloaded\n");
}
module_init(hello_init);
module_exit(hello_exit);makefile
undefinedc
// hello.c — minimal loadable kernel module
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Minimal hello world module");
MODULE_VERSION("1.0");
static int __init hello_init(void)
{
printk(KERN_INFO "hello: module loaded\n");
return 0; // non-zero = load failure
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "hello: module unloaded\n");
}
module_init(hello_init);
module_exit(hello_exit);makefile
undefinedMakefile — must be exactly this structure for Kbuild
Makefile — must be exactly this structure for Kbuild
obj-m := hello.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
```bashobj-m := hello.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
```bashBuild
Build
make
make
Load
Load
sudo insmod hello.ko
sudo insmod hello.ko
Check it loaded
Check it loaded
lsmod | grep hello
dmesg | tail -5 # see printk output
lsmod | grep hello
dmesg | tail -5 # see printk output
Unload
Unload
sudo rmmod hello
sudo rmmod hello
Show module info
Show module info
modinfo hello.ko
undefinedmodinfo hello.ko
undefined2. Module parameters
2. 模块参数
c
#include <linux/moduleparam.h>
static int count = 1;
static char *name = "world";
// module_param(variable, type, permissions)
// permissions: 0 = no sysfs entry, S_IRUGO = readable, S_IWUSR = writable
module_param(count, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(count, "Number of times to print (default: 1)");
module_param(name, charp, S_IRUGO);
MODULE_PARM_DESC(name, "Name to greet (default: world)");
static int __init hello_init(void)
{
int i;
for (i = 0; i < count; i++)
printk(KERN_INFO "hello: Hello, %s!\n", name);
return 0;
}bash
undefinedc
#include <linux/moduleparam.h>
static int count = 1;
static char *name = "world";
// module_param(variable, type, permissions)
// permissions: 0 = no sysfs entry, S_IRUGO = readable, S_IWUSR = writable
module_param(count, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(count, "Number of times to print (default: 1)");
module_param(name, charp, S_IRUGO);
MODULE_PARM_DESC(name, "Name to greet (default: world)");
static int __init hello_init(void)
{
int i;
for (i = 0; i < count; i++)
printk(KERN_INFO "hello: Hello, %s!\n", name);
return 0;
}bash
undefinedPass parameters at load time
Pass parameters at load time
sudo insmod hello.ko count=3 name="kernel"
sudo insmod hello.ko count=3 name="kernel"
Modify at runtime (if S_IWUSR set)
Modify at runtime (if S_IWUSR set)
echo 5 > /sys/module/hello/parameters/count
undefinedecho 5 > /sys/module/hello/parameters/count
undefined3. /proc filesystem interface
3. /proc文件系统接口
c
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static struct proc_dir_entry *proc_entry;
static int mymod_show(struct seq_file *m, void *v)
{
seq_printf(m, "Counter: %d\n", my_counter);
seq_printf(m, "Status: %s\n", my_status ? "active" : "idle");
return 0;
}
static int mymod_open(struct inode *inode, struct file *file)
{
return single_open(file, mymod_show, NULL);
}
static const struct proc_ops mymod_fops = {
.proc_open = mymod_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init mymod_init(void)
{
proc_entry = proc_create("mymod", 0444, NULL, &mymod_fops);
if (!proc_entry)
return -ENOMEM;
return 0;
}
static void __exit mymod_exit(void)
{
proc_remove(proc_entry);
}bash
cat /proc/mymodc
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
static struct proc_dir_entry *proc_entry;
static int mymod_show(struct seq_file *m, void *v)
{
seq_printf(m, "Counter: %d\n", my_counter);
seq_printf(m, "Status: %s\n", my_status ? "active" : "idle");
return 0;
}
static int mymod_open(struct inode *inode, struct file *file)
{
return single_open(file, mymod_show, NULL);
}
static const struct proc_ops mymod_fops = {
.proc_open = mymod_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init mymod_init(void)
{
proc_entry = proc_create("mymod", 0444, NULL, &mymod_fops);
if (!proc_entry)
return -ENOMEM;
return 0;
}
static void __exit mymod_exit(void)
{
proc_remove(proc_entry);
}bash
cat /proc/mymod4. sysfs interface
4. sysfs接口
c
#include <linux/kobject.h>
#include <linux/sysfs.h>
static struct kobject *mymod_kobj;
static int mymod_value = 42;
static ssize_t value_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", mymod_value);
}
static ssize_t value_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "%d", &mymod_value);
return count;
}
static struct kobj_attribute value_attr =
__ATTR(value, 0664, value_show, value_store);
static int __init mymod_init(void)
{
mymod_kobj = kobject_create_and_add("mymod", kernel_kobj);
if (!mymod_kobj) return -ENOMEM;
return sysfs_create_file(mymod_kobj, &value_attr.attr);
}
static void __exit mymod_exit(void)
{
sysfs_remove_file(mymod_kobj, &value_attr.attr);
kobject_put(mymod_kobj);
}bash
cat /sys/kernel/mymod/value
echo 100 > /sys/kernel/mymod/valuec
#include <linux/kobject.h>
#include <linux/sysfs.h>
static struct kobject *mymod_kobj;
static int mymod_value = 42;
static ssize_t value_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", mymod_value);
}
static ssize_t value_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "%d", &mymod_value);
return count;
}
static struct kobj_attribute value_attr =
__ATTR(value, 0664, value_show, value_store);
static int __init mymod_init(void)
{
mymod_kobj = kobject_create_and_add("mymod", kernel_kobj);
if (!mymod_kobj) return -ENOMEM;
return sysfs_create_file(mymod_kobj, &value_attr.attr);
}
static void __exit mymod_exit(void)
{
sysfs_remove_file(mymod_kobj, &value_attr.attr);
kobject_put(mymod_kobj);
}bash
cat /sys/kernel/mymod/value
echo 100 > /sys/kernel/mymod/value5. Character device
5. 字符设备
c
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "mydev"
#define BUF_SIZE 1024
static int major;
static struct cdev my_cdev;
static char kernel_buf[BUF_SIZE];
static int mydev_open(struct inode *inode, struct file *file) { return 0; }
static int mydev_release(struct inode *inode, struct file *file) { return 0; }
static ssize_t mydev_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
size_t to_copy = min(len, (size_t)BUF_SIZE);
if (copy_to_user(buf, kernel_buf, to_copy)) return -EFAULT;
return to_copy;
}
static ssize_t mydev_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
size_t to_copy = min(len, (size_t)(BUF_SIZE - 1));
if (copy_from_user(kernel_buf, buf, to_copy)) return -EFAULT;
kernel_buf[to_copy] = '\0';
return to_copy;
}
static const struct file_operations mydev_fops = {
.owner = THIS_MODULE,
.open = mydev_open,
.release = mydev_release,
.read = mydev_read,
.write = mydev_write,
};
static int __init mydev_init(void)
{
major = register_chrdev(0, DEVICE_NAME, &mydev_fops);
if (major < 0) return major;
printk(KERN_INFO "mydev: registered with major %d\n", major);
return 0;
}bash
undefinedc
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "mydev"
#define BUF_SIZE 1024
static int major;
static struct cdev my_cdev;
static char kernel_buf[BUF_SIZE];
static int mydev_open(struct inode *inode, struct file *file) { return 0; }
static int mydev_release(struct inode *inode, struct file *file) { return 0; }
static ssize_t mydev_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
size_t to_copy = min(len, (size_t)BUF_SIZE);
if (copy_to_user(buf, kernel_buf, to_copy)) return -EFAULT;
return to_copy;
}
static ssize_t mydev_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
size_t to_copy = min(len, (size_t)(BUF_SIZE - 1));
if (copy_from_user(kernel_buf, buf, to_copy)) return -EFAULT;
kernel_buf[to_copy] = '\0';
return to_copy;
}
static const struct file_operations mydev_fops = {
.owner = THIS_MODULE,
.open = mydev_open,
.release = mydev_release,
.read = mydev_read,
.write = mydev_write,
};
static int __init mydev_init(void)
{
major = register_chrdev(0, DEVICE_NAME, &mydev_fops);
if (major < 0) return major;
printk(KERN_INFO "mydev: registered with major %d\n", major);
return 0;
}bash
undefinedCreate device node (after loading module)
Create device node (after loading module)
sudo mknod /dev/mydev c $(cat /proc/devices | grep mydev | awk '{print $1}') 0
echo "test" > /dev/mydev
cat /dev/mydev
undefinedsudo mknod /dev/mydev c $(cat /proc/devices | grep mydev | awk '{print $1}') 0
echo "test" > /dev/mydev
cat /dev/mydev
undefined6. Debugging with KGDB and ftrace
6. 使用KGDB和ftrace进行调试
bash
undefinedbash
undefinedKGDB — kernel GDB via serial/network
KGDB — kernel GDB via serial/network
Boot with: kgdboc=ttyS0,115200 kgdbwait
Boot with: kgdboc=ttyS0,115200 kgdbwait
Or over network: kgdboe=@192.168.1.10/,@192.168.1.11/
Or over network: kgdboe=@192.168.1.10/,@192.168.1.11/
On debug host:
On debug host:
gdb vmlinux
(gdb) target remote /dev/ttyS0
(gdb) set architecture i386:x86-64:intel
(gdb) info registers
gdb vmlinux
(gdb) target remote /dev/ttyS0
(gdb) set architecture i386:x86-64:intel
(gdb) info registers
ftrace — kernel function tracer
ftrace — kernel function tracer
echo function > /sys/kernel/debug/tracing/current_tracer
echo mymod_write > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace
echo function > /sys/kernel/debug/tracing/current_tracer
echo mymod_write > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace
Dynamic debug — enable pr_debug() output
Dynamic debug — enable pr_debug() output
echo "module hello +p" > /sys/kernel/debug/dynamic_debug/control
undefinedecho "module hello +p" > /sys/kernel/debug/dynamic_debug/control
undefined7. Module signing (Secure Boot)
7. 模块签名(Secure Boot)
bash
undefinedbash
undefinedGenerate signing key
Generate signing key
openssl req -new -x509 -newkey rsa:2048
-keyout signing_key.pem -out signing_cert.pem
-days 365 -subj "/CN=Module Signing Key/" -nodes
-keyout signing_key.pem -out signing_cert.pem
-days 365 -subj "/CN=Module Signing Key/" -nodes
openssl req -new -x509 -newkey rsa:2048
-keyout signing_key.pem -out signing_cert.pem
-days 365 -subj "/CN=Module Signing Key/" -nodes
-keyout signing_key.pem -out signing_cert.pem
-days 365 -subj "/CN=Module Signing Key/" -nodes
Sign the module
Sign the module
/usr/src/linux-headers-$(uname -r)/scripts/sign-file
sha256 signing_key.pem signing_cert.pem hello.ko
sha256 signing_key.pem signing_cert.pem hello.ko
/usr/src/linux-headers-$(uname -r)/scripts/sign-file
sha256 signing_key.pem signing_cert.pem hello.ko
sha256 signing_key.pem signing_cert.pem hello.ko
Import certificate to MOK database
Import certificate to MOK database
sudo mokutil --import signing_cert.pem
sudo mokutil --import signing_cert.pem
(requires reboot and MOK enrollment at UEFI)
(requires reboot and MOK enrollment at UEFI)
For Kbuild system details, see [references/kbuild-basics.md](references/kbuild-basics.md).
有关Kbuild系统的详细信息,请参阅[references/kbuild-basics.md](references/kbuild-basics.md)。Related skills
相关技能
- Use for userspace kernel tracing without modules
skills/observability/ebpf - Use for GDB session management with KGDB
skills/debuggers/gdb - Use for inspecting module ELF structure
skills/binaries/elf-inspection
- 若需在不使用模块的情况下进行用户态内核追踪,请使用
skills/observability/ebpf - 若需使用KGDB进行GDB会话管理,请使用
skills/debuggers/gdb - 若需检查模块ELF结构,请使用
skills/binaries/elf-inspection