Linux字符设备驱动的实现与QEMU验证

Linux字符设备驱动实现与验证

本文总结 simple_demo 这个最小 Linux 字符设备驱动 demo 的功能,并给出完整代码与最小编译、加载、验证方法。

假定内核已经提前编译完成,且可直接使用:

KDIR=~/workspace/Linux/linux

1. Demo 功能概述

simple_demo 是一个基于 miscdevice 的最小字符设备驱动。

加载模块后,内核会创建设备节点:

sh 复制代码
/dev/simple_demo

这个 demo 支持最基本的两类操作:

  • read():读取驱动内部保存的字符串
  • write():把用户写入的字符串保存到驱动内部缓冲区

默认行为

  • 模块加载后,默认内容为:
text 复制代码
hello from simple_demo
  • 用户向 /dev/simple_demo 写入新内容后,后续再读时就会返回最新写入的数据

2. 代码实现思路

这个 demo 的实现非常简单,核心只有四部分:

  • 一个全局缓冲区:保存当前字符串内容
  • 一个 read():把内核缓冲区内容拷给用户态
  • 一个 write():把用户态内容写入内核缓冲区

设备注册方式使用 miscdevice,这样不需要自己手动分配主设备号。

3. 完整代码

C 复制代码
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>

#define SIMPLE_DEMO_MAX_MSG_LEN 256
#define SIMPLE_DEMO_DEFAULT_MSG "hello from simple_demo\n"

static DEFINE_MUTEX(simple_demo_lock);
static char simple_demo_msg[SIMPLE_DEMO_MAX_MSG_LEN] = SIMPLE_DEMO_DEFAULT_MSG;
static size_t simple_demo_msg_len = sizeof(SIMPLE_DEMO_DEFAULT_MSG) - 1;

static ssize_t simple_demo_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	ssize_t ret;

	mutex_lock(&simple_demo_lock);
	ret = simple_read_from_buffer(buf, count, ppos, simple_demo_msg, simple_demo_msg_len);
	mutex_unlock(&simple_demo_lock);

	return ret;
}

static ssize_t simple_demo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	size_t copy_len;

	if (!count)
		return 0;

	copy_len = min(count, (size_t)(SIMPLE_DEMO_MAX_MSG_LEN - 1));

	mutex_lock(&simple_demo_lock);
	if (copy_from_user(simple_demo_msg, buf, copy_len)) {
		mutex_unlock(&simple_demo_lock);
		return -EFAULT;
	}
	simple_demo_msg[copy_len] = '\0';
	simple_demo_msg_len = copy_len;
	mutex_unlock(&simple_demo_lock);

	return count;
}

static const struct file_operations simple_demo_fops = {
	.owner = THIS_MODULE,
	.read = simple_demo_read,
	.write = simple_demo_write,
	.llseek = noop_llseek,
};

static struct miscdevice simple_demo_miscdev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "simple_demo",
	.fops = &simple_demo_fops,
	.mode = 0666,
};

static int __init simple_demo_init(void)
{
	int ret;

	ret = misc_register(&simple_demo_miscdev);
	if (ret)
		return ret;

	pr_info("simple_demo: loaded (/dev/%s)\n", simple_demo_miscdev.name);
	return 0;
}

static void __exit simple_demo_exit(void)
{
	misc_deregister(&simple_demo_miscdev);
	pr_info("simple_demo: unloaded\n");
}

module_init(simple_demo_init);
module_exit(simple_demo_exit);

MODULE_AUTHOR("demo");
MODULE_DESCRIPTION("Simple misc char device driver demo");
MODULE_LICENSE("GPL");

4. 编译方法

假定内核已经编译好,内核代码位于~/workspace/Linux/linux,直接编这个驱动模块即可。

进入驱动Demo目录:

bash 复制代码
cd ~/workspace/Lab/drivers

编译命令:

bash 复制代码
make clean KDIR=~/workspace/Linux/linux
make KDIR=~/workspace/Linux/linux

编译成功后会生成:

text 复制代码
simple_demo.ko

可以再检查一下模块版本信息:

bash 复制代码
modinfo -F vermagic simple_demo.ko

输出中应包含:

text 复制代码
7.1.0-rc2+

输出必须等于 QEMU (我们用QEMU启动的内核)里的 uname -r

5. 加载与验证

宿主机与qemu之间传递文件可以参考《使用额外ext4磁盘镜像在QEMU中传递与加载内核模块》。

假设 simple_demo.ko 已经放到 QEMU 可访问目录 /mnt/host,在 QEMU 中执行:

sh 复制代码
insmod /mnt/host/simple_demo.ko
ls -l /dev/simple_demo

读取默认内容:

sh 复制代码
cat /dev/simple_demo

写入新内容并再次读取:

sh 复制代码
echo -n "from_user\n" > /dev/simple_demo
cat /dev/simple_demo

查看日志:

sh 复制代码
dmesg | tail -n 20

卸载模块:

sh 复制代码
rmmod simple_demo

6. 上层应用如何使用

上层应用把它当成普通字符设备文件即可,直接对 /dev/simple_demo 做文件操作:

  • open("/dev/simple_demo", O_RDWR)
  • read()
  • write()
  • close()

最简单的 shell 使用方式:

sh 复制代码
cat /dev/simple_demo
echo -n "hello driver\n" > /dev/simple_demo
cat /dev/simple_demo
相关推荐
手可摘星辰的少年2 小时前
使用额外ext4磁盘镜像在QEMU中传递与加载内核模块
linux
hai3152475432 小时前
libcore_final.c —— 九章数流矩阵系统
linux·运维·网络
zh路西法2 小时前
【RDKX5交叉编译】基于 QEMU 的 RDK X5 ARM64 rootfs 镜像定制与 chroot 开发环境搭建
linux
iRayCheung2 小时前
virtualbox安装的ubuntu系统跑numpy报错
linux·ubuntu·numpy
Dlrb12113 小时前
Linux系统编程-信号量(线程同步机制)
linux·条件变量·互斥锁·信号量·线程同步
无限进步_3 小时前
Linux进程等待——wait、waitpid与僵尸进程
linux·运维·服务器·开发语言
2401_834636993 小时前
Linux集群技术-高可用与负载均衡实战解析
linux·运维·负载均衡
吠品3 小时前
处理 Python 类继承中那些变来变去的初始化参数
linux·前端·python
帅大大的架构之路3 小时前
linux上面的一些小知识点
linux·运维·服务器