当前位置: 首页 > news >正文

驱动读写实验

前言

  在编写驱动读写的时候,有个疑问:在内核中有一段固定的内存空间,假如应用多个进程在同时且连续的读写时,会发生错乱的情况吗?

验证平台:qemu 运行linux kernel 4.0 的虚拟机上进行验证,busybox 使用的是静态编译的库,故应用也需要静态编译。

驱动代码设计

驱动设计思路

  • 内核中使用一个数组作为上述的固定内存空间。
  • 驱动初始化注册字符设备并自动创建设备节点 /dev/rivotek_0。
  • 实现驱动读写函数,写入时将应用层的字符写入到数组中,并打印写入的字符串;读取时,从数组中将该字符串传递给应用,驱动打印该字符串。
  • 驱动退出时,销毁注册时创建的节点和注册的字符设备。

实现代码如下

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/device.h>#define CDE_NAME "rivotek_cdev"unsigned char lcdev_buff[32] = {0};struct my_char_dev 
{unsigned int maj;   unsigned int mio;   unsigned int count;struct cdev *cdev;struct class *rivotek_class;};struct my_char_dev *lcdev;static int lcdev_open(struct inode *inode, struct file *file)
{printk(KERN_INFO"lcdev open\n");return 0;
}static int lcdev_release (struct inode *inode, struct file *file)
{printk(KERN_INFO"lcdev release\n");return 0;
}static ssize_t lcdev_write(struct file *l_file, const char __user *buf, size_t count, loff_t *f_ops)
{int ret = -1;ret = copy_from_user((void *)lcdev_buff, buf, sizeof(lcdev_buff));if(ret)printk(KERN_ERR"Write error,ret=%d\n",ret);printk(KERN_ERR"%s: %s,ret=%d\n",__FUNCTION__,lcdev_buff,ret);return ret;
}static ssize_t lcdev_read(struct file *file, char __user *buf, size_t count, loff_t *f_ops)
{int ret = -1;ret = copy_to_user((void *)buf, lcdev_buff, sizeof(lcdev_buff));if(ret)printk(KERN_ERR"Write error,ret=%d\n",ret);printk(KERN_ERR"%s: %s,ret=%d\n", __FUNCTION__,lcdev_buff,ret);return ret;
}static const struct file_operations lcdev_fops = {.owner = THIS_MODULE,.open = lcdev_open,.write = lcdev_write,.read  = lcdev_read,.release	= lcdev_release,};static int __init char_test_init(void)
{int ret;dev_t dev_n = 0;int i = 0;lcdev = kmalloc(sizeof(struct my_char_dev), GFP_KERNEL);if(!lcdev) {printk(KERN_ERR"No memory for lcdev");ret =  -ENOMEM;goto out;}printk(KERN_ALERT"kmalloc ok \n");lcdev->maj = 0;lcdev->mio = 0;lcdev->count = 1;ret = alloc_chrdev_region(&dev_n, lcdev->mio, lcdev->count, CDE_NAME);if(0 > ret) {printk(KERN_ERR"register failed\n");goto register_err;}lcdev->maj = MAJOR(dev_n);lcdev->mio = MINOR(dev_n);printk(KERN_ALERT"register char dev ok ,ret:%d\n", ret);lcdev->cdev = cdev_alloc();if (!lcdev->cdev)goto register_err;cdev_init(lcdev->cdev, &lcdev_fops);ret = cdev_add(lcdev->cdev,MKDEV(lcdev->maj,lcdev->mio), lcdev->count);if(ret < 0)goto add_fail;printk(KERN_ALERT"maj: %d ,mio:%d\n", lcdev->maj, lcdev->mio);lcdev->rivotek_class = class_create(THIS_MODULE, "rivotek");if (IS_ERR(lcdev->rivotek_class)) {printk("Class create failed\n");	ret = PTR_ERR(lcdev->rivotek_class);goto register_err;}for(i = 0; i < lcdev->count; i++){char buf[16];sprintf(buf, "rivotek_%d", i);device_create(lcdev->rivotek_class, NULL, MKDEV(lcdev->maj, i), NULL, buf);memset(buf, 0, sizeof(buf));}return 0;add_fail:kobject_put(&lcdev->cdev->kobj);register_err:unregister_chrdev_region(MKDEV(lcdev->maj,lcdev->mio), lcdev->count);if(lcdev)kfree(lcdev);return -1;out:return ret;}static void __exit char_test_exit(void)
{unregister_chrdev(lcdev->maj, CDE_NAME);kfree(lcdev);printk(KERN_ALERT"char test exit\n");
}module_init(char_test_init);
module_exit(char_test_exit);MODULE_LICENSE("GPL");

应用代码设计

应用代码设计思路:

  • 设计一个带参的应用,传入设备节点 和 写入该节点 的字符串
  • 打开传入的设备节点
  • while 死循环中将字符串写入设备节点,写入完成后打印当前的pid和提示“write done”;2s 后从该节点读取字符串并打印读取到的内容。

代码实现如下

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,char *argv[])
{int ret = -1;int fd = -1;unsigned char buf[32];if (3 > argc) {printf("%s [path] [string]\n", argv[0]);return -1;}fd = open(argv[1], O_RDWR);if ( 0 > fd) {printf("%s open failed\n", argv[1]);return fd;}printf("open ok, fd=%d\n", fd);while(1){memset(buf, 0, sizeof(buf));sprintf(buf, argv[2], sizeof(buf));ret = write (fd, (void *)buf, sizeof(buf));if (0 > ret) {printf("Write fd=%d srting: %s error \n",fd ,argv[2]);return ret;}memset(buf, 0, sizeof(buf));printf("%d Write done\t",getpid());ret = read(fd, (void *)buf, sizeof(buf));if (0 > ret) {printf("Read fd=%d  error \n",fd );return ret;}printf("read information: %s\n", buf);sleep(2);}return 0;
}

验证结果

  • 执行 “ /wwp/rivote_driver_test_tmp /dev/rivotek_0  123 &”,向驱动中读写字符串“abcd”

        

从打印结果来看,当前进程pid 为705,写入和读取都是“123”,均是正常的行为。

  • 继续执行“/wwp/rivote_driver_test_tmp /dev/rivotek_0  abcd &”, 向驱动中读写字符串“abcd”

1)从以上打印看,写入字符创abcd 的应用进程号是706,且读写都是正常的

2)先运行的应用pid 为 705 的进程,也在继续运行,且两个进程运行相互不干扰。

综上,驱动中同一个空间,多个应用读写的时候,是互不影响的。

http://www.xdnf.cn/news/248995.html

相关文章:

  • GRPO:利用组内平均奖励来计算优势
  • 蓝桥杯Python案例
  • 计算机组成原理实验(5) 堆栈寄存器实验
  • 2025五一杯数学建模ABC题赛题已出
  • ctfshow web入门 web44
  • Python学习笔记(第一部分)
  • 基于深度学习的人脸属性识别算法研究
  • 随机森林实战:从原理到垃圾邮件分类
  • 超稳定性理论
  • 第十四章:生产之路:LLM 应用部署、运维与优化
  • MOOS-ivp使用(一)——水下机器人系统的入门与使用
  • 【2025最新面经】暑期实习常问知识点
  • 前端面经 4
  • 【C++学习笔记】深入理解虚函数和多态
  • 简单句练习--语法基础
  • 50、【OS】【Nuttx】【OSTest】参数解析:函数定义
  • 当算力遇上堵车:AI如何让城市血管不再“血栓”?
  • OpenStack Yoga版安装笔记(25)Nova Cell理解
  • 黑马Java基础笔记-6
  • 伽利略如何测量光速?一场跨越山头的失败实验
  • VBA数据结构深度解析:基础类型、自定义类型与数组操作指南
  • Dagster资产工厂实战:从Python到YAML配置的高效ETL流程
  • 408真题笔记
  • 第十三章:LLM 应用质量保证:评估体系、工具与实战
  • 深入解析三大查找算法:线性查找、二分查找与哈希查找的原理与应用
  • 进程(Process)和操作系统(Operation System)
  • ctfshow web入门 web46
  • 用spring-boot-maven-plugin打包成单个jar有哪些缺点优化方案
  • pandas读取Excel数据(.xlsx和.xls)到treeview
  • JavaScript如何实现类型判断?