内核模块编写

好,我明白了,你是要一个实验报告式的答案:

 

  • 一开始就把全部需要的文件和最终完整代码给出来。
  • 后续每一步只描述目的 → 运行哪个文件 → 操作命令 → 验证命令 → 预期输出,不重复贴代码。

 

 

这样报告既精简,又符合实验报告的层次性。

 

 

 

 

一、实验文件说明

 

 

本实验一共需要 2 个文件:

 

  1. mychardev.c — 内核模块 C 源码(最终版本,已经包含全部功能)
  2. Makefile — 编译内核模块的构建文件

 

 

 

 

 

mychardev.c(最终版)

 

#include <linux/init.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/uaccess.h>

#include <linux/string.h>

 

#define DEVICE_NAME "mychardev"

#define BUF_LEN 256

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Your Name");

MODULE_DESCRIPTION("Char device with optional uppercase output");

 

static int major_num = 0;

static char device_buffer[BUF_LEN] = {0};

static int cap = 0;

 

module_param(cap, int, 0644);

MODULE_PARM_DESC(cap, "Set to 1 to convert input to uppercase");

 

static ssize_t dev_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)

{

    size_t i = 0;

    size_t copy_len = (len < BUF_LEN - 1) ? len : (BUF_LEN - 1);

    memset(device_buffer, 0, BUF_LEN);

 

    if (copy_from_user(device_buffer, buf, copy_len) != 0) {

        printk(KERN_ERR "copy_from_user failed\n");

        return -EFAULT;

    }

 

    if (cap == 1) {

        for (i = 0; i < copy_len; i++) {

            if (device_buffer[i] >= 'a' && device_buffer[i] <= 'z') {

                device_buffer[i] -= 32;

            }

        }

    }

 

    printk(KERN_INFO "Output: %s\n", device_buffer);

    return copy_len;

}

 

static struct file_operations fops = {

    .owner = THIS_MODULE,

    .write = dev_write

};

 

static int __init mychardev_init(void)

{

    major_num = register_chrdev(0, DEVICE_NAME, &fops);

    if (major_num < 0) {

        printk(KERN_ERR "Failed to register char device\n");

        return major_num;

    }

    printk(KERN_INFO "Module loaded, major = %d, cap=%d\n", major_num, cap);

    printk(KERN_INFO "Create device: mknod /dev/%s c %d 0\n", DEVICE_NAME, major_num);

    return 0;

}

 

static void __exit mychardev_exit(void)

{

    unregister_chrdev(major_num, DEVICE_NAME);

    printk(KERN_INFO "Module unloaded\n");

}

 

module_init(mychardev_init);

module_exit(mychardev_exit);

 

 

 

 

Makefile

 

obj-m += mychardev.o

 

all:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

 

clean:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

 

 

 

 

二、分阶段实验步骤

 

 

注意:每个阶段都运行 同一个 mychardev.c 文件(最终版),只是关注不同功能是否正常。

 

 

 

 

阶段 1:模块框架验证

 

 

目的

验证模块能正常编译、加载、卸载,并在 dmesg 输出信息。

 

运行文件

mychardev.c(最终版)

 

操作命令

make

sudo insmod mychardev.ko

验证成功的命令

dmesg | tail -n 5

预期输出

[xxxx.xx] Module loaded, major = <num>, cap=0

[xxxx.xx] Create device: mknod /dev/mychardev c <num> 0

卸载:

sudo rmmod mychardev

dmesg | tail -n 5

预期:

[xxxx.xx] Module unloaded

 

 

 

 

阶段 2:注册字符设备验证

 

 

目的

确认 major number 正常分配,能够手动创建设备文件。

 

运行文件

mychardev.c(最终版)

 

操作命令

sudo insmod mychardev.ko

sudo mknod /dev/mychardev c <major> 0

ls -l /dev/mychardev

验证成功的命令

ls -l /dev/mychardev

预期输出

crw-r--r-- 1 root root 240, 0 Aug  8 12:00 /dev/mychardev

卸载并删除设备文件:

sudo rmmod mychardev

sudo rm /dev/mychardev

 

 

 

 

阶段 3:write 功能验证

 

 

目的

验证能向 /dev/mychardev 写入数据并在 dmesg 打印。

 

运行文件

mychardev.c(最终版)

 

操作命令

sudo insmod mychardev.ko

sudo mknod /dev/mychardev c <major> 0

echo "hello kernel" > /dev/mychardev

验证成功的命令

dmesg | tail -n 5

预期输出

[xxxx.xx] Output: hello kernel

 

 

 

 

阶段 4:cap 参数验证

 

 

目的

验证加载模块时设置 cap=1 能将输出转为大写。

 

运行文件

mychardev.c(最终版)

 

操作命令

sudo insmod mychardev.ko cap=1

sudo mknod /dev/mychardev c <major> 0

echo "hello kernel" > /dev/mychardev

验证成功的命令

dmesg | tail -n 5

预期输出

[xxxx.xx] Output: HELLO KERNEL

卸载并删除设备文件:

sudo rmmod mychardev

sudo rm /dev/mychardev

 

 

 

这样写的实验报告好处是:

 

  • 一开始就给出完整文件和代码,后面不用重复贴代码。
  • 每一步的目标、运行文件、命令和预期结果都清晰独立,方便截图验证。

 

 

 

 

我可以帮你把这份内容直接排版成实验报告模板格式(带表格和截图占位符),这样你直接填截图就能交作业。

你要我帮你做这个实验报告模板吗?这样可以直接生成可提交的文档结构。

 
posted @ 2025-08-08 10:08  balan学嵌入式  阅读(10)  评论(0)    收藏  举报