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

内核驱动踩坑记录

内核驱动踩坑记录


一:银河麒麟操作系统+飞腾处理器
此处省略一万字

二:用户空间访问问题
块设备驱动提供ioctl接口供用户直接向特定扇区读写数据,在ioctl系统调用参数中传递用户缓冲区的地址。ioctl内核处理函数中直接将请求打包成相应的命令,加入SSD请求队列等待执行。由于未实现中断功能,利用定时器定时轮询对应位置查看命令执行情况并在设备空闲时发送请求。此时调用copy_from_user函数失败。这是因为定时器回调函数是异步执行的,它类似于一种“软件中断”,而且是处于非进程的上下文中,所以回调函数必须遵守以下规则:

  1. 没有 current 指针、不允许访问用户空间。因为没有进程上下文,相关代码和被中断的进程没有任何联系。
  2. 不能执行休眠(或可能引起休眠的函数)和调度。
  3. 任何被访问的数据结构都应该针对并发访问进行保护,以防止竞争条件。
    inux内核timer执行上下文,内核定时器的使用(好几个例子add_timer)
    解决:
    如果是写命令,先将数据写入申请的内核缓冲区,再将内核缓冲区的地址写入命令。如果是读命令,先将读到的数据写入内核缓冲区,再将数据写入用户缓冲区。
    ioctl请求的一般执行过程为:①解析参数 ②申请内核缓冲区存放数据 ③ 将请求封装成命令,加入命令队列 ④等待命令执行完成,并执行必要的数据传输工作。

三:模块卸载出错
有时候编写代码时并不会检查函数返回值等信息,有时候资源并没有申请成功,而在.remove函数中却照常进行了资源释放,或者申请了资源却忘了在remove函数中进行释放,便会造成空指针 死机等一系列的后果。
例如在.probe函数中注册了定时器却忘了注销,注册块设备失败却照常注销块设备,get_device与put_device数目不一致

add_timer(&hps_dev->timer);                         //注册定时器
del_timer(&hps_dev->timer);                       //注销定时器
device_add_disk(hps_dev->dev, hps_dev->disk, hps_attr_groups); // 注册块设备
del_gendisk(hps_dev->disk);                       // 移除块设备
hps_dev->dev = get_device(&pdev->dev);			  // 增加设备计数
put_device(hps_dev->dev);                         // 减小设备计数

所以比较安全的方式就是增加出错处理代码或在资源释放时判断是否持有。

ret = request();
if(ret!=0){
	// 出错处理
}

if(hold(p)) release p;

四:DMA缓冲区大小问题
dma_alloc_coherent函数申请超过4M便会报错,配置CMA使DMA能够申请更大的空间,这可能需要需要重新编译内核(如果高版本宿主机编译内核建议先通过deb安装文件切换至相近版本的内核,再通过源码编译内核)。

dev->data_buf = dma_alloc_coherent(dev->dev, MAX_DATA_SIZE, &dev->data_buf_dma_addr, GFP_KERNEL);

参考博客:
dma_alloc_coherent 申请内存用法和问题总结
在Linux内核模块中使用CMA内存分配
在这里插入图片描述
大致步骤如下:

cat /boot/config-$(uname -r) | grep DMA_CMA  # 查看当前内核是否开启了CMA功能
如果不存在则需要重新编译内核,建议配置内核时顺带勾选kgdb选项
CONFIG_DMA_CMA选项没在memuconfig找到,可直接通过vim .config修改,也可将其他的CMA选项打开
在编译内核是会选择CMA空间大小,后面也可以在grub配置文件中修改相应大小。
cat /proc/meminfo # 查看是否修改成功
CmaTotal:        1048576 kB
CmaFree:         1048576 kB
dmesg | grep cma # 显示内核启动时cma相关信息
配置成功后就能申请更大的连续物理内存

在这里插入图片描述
五:linux内存页大小问题
在用户程序中使用mmap系统调用,传入的映射长度为32k,可是内核mmap处理函数中vm_area的长度却显示为64k。

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void* start,size_t length);

解决:

getconf PAGE_SIZE # 查看当前页大小
65536

mmap 必须以PAGE_SIZE为单位进行映射,而内存也只能以页为单位进行映射,若要映射非PAGE_SIZE整数倍的地址范围,要先进行内存对齐,强行以PAGE_SIZE的倍数大小进行映射。由于传入长度小于64k,进行了一次向上取整。故重新编译内核,在menuconfig中修改page size。

六:网络不稳定,同属于一个局域网却不能ping通
通过打印内核启动时的信息可以发现网卡在一直自动协商连接速度,通过ethtool工具关闭自动协商功能即可。

# 将网卡eth2速度固定1000M,双工,且关闭自动协商
sudo ethtool -s eth2 speed 1000 duplex full autoneg off

Linux 关闭链路自动协商功能

相关文章:

  • 半导体中的杂质和缺陷能级
  • SSM毕设项目大学生心理咨询系统792l6(java+VUE+Mybatis+Maven+Mysql)
  • 嵌入式学习的第二天
  • R语言(4) plot函数介绍
  • JVM -- 垃圾回收器7种(四)
  • 模型调优:验证集的作用(就是为了调整超参数)
  • PyQt5之消息对话框
  • java计算机毕业设计校友闲置书籍管理平台源代码+数据库+系统+lw文档
  • Interactron | 体现自适应的目标检测器
  • javaEE---CSS
  • PCIE操作基础原理
  • Windows系统SVG图片预览插件
  • 2022.10.1模拟赛
  • 西瓜书研读——第三章 线性模型: 线性判别分析 LDA
  • 云计算概论 --云安全机制
  • 【前端学习】-粗谈选择器
  • AngularJS指令开发(1)——参数详解
  • Facebook AccountKit 接入的坑点
  • happypack两次报错的问题
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JavaScript-Array类型
  • JavaScript服务器推送技术之 WebSocket
  • javascript面向对象之创建对象
  • PaddlePaddle-GitHub的正确打开姿势
  • PHP 7 修改了什么呢 -- 2
  • underscore源码剖析之整体架构
  • vuex 学习笔记 01
  • Webpack 4 学习01(基础配置)
  • webpack+react项目初体验——记录我的webpack环境配置
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 如何在GitHub上创建个人博客
  • 数据可视化之 Sankey 桑基图的实现
  • 在weex里面使用chart图表
  • 怎么将电脑中的声音录制成WAV格式
  • #pragma once与条件编译
  • #在 README.md 中生成项目目录结构
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (04)odoo视图操作
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (二)Linux——Linux常用指令
  • (二)pulsar安装在独立的docker中,python测试
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (十六)一篇文章学会Java的常用API
  • (五)Python 垃圾回收机制
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • ... 是什么 ?... 有什么用处?
  • .net 7 上传文件踩坑
  • .NET Core 和 .NET Framework 中的 MEF2
  • .Net 知识杂记
  • .NET中的十进制浮点类型,徐汇区网站设计
  • .sys文件乱码_python vscode输出乱码
  • @AliasFor注解