写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文!
本博客全网唯一合法URL:https://www.cnblogs.com/acm-icpcer/p/8029656.html
最近学院里的nfc老师要我们做个设备驱动,之前从没接手过这个东西,加上老师给的材料错误也是一大堆,搞了差不多一个星期才搞出来。特此写一个博客,以免后来人和我一样跳坑。
总体考虑
要去写设备驱动程序,说白了就三大步骤:下载内核源码构建内核源码树(也就是下载你的目的内核源码包并解压就行了)、编译内核(这样才能让操作系统感知自己写的驱动程序)、写代码(编写内核程序并编译测试)。这三步哪一步都很艰难。
我是在自己笔记本上用虚拟机VMware装的ubuntu操作系统,相比于装双系统有一大缺点和一大优点,优点是将编译好的新内核装入操作系统时不用担心系统崩溃,缺点是装虚拟机的时候没考虑周全,搞得虚拟机的硬盘太小了,估计容量不够用。
那么综合考虑之后,对于我来说是四大步骤:1、给虚拟机扩容;2、下载内核源码构建内核源码树;3、编译内核;4、写代码。
下面来一一介绍:
1、虚拟机扩容
(1)虚拟机逻辑扩盘。仅仅在这一步扩盘是完全不够的!还要在虚拟机内部设置挂载,不然的话虚拟机无法感知到你扩展的硬盘。这相当于你给一台实际的台式电脑加了一块新硬盘后,还要在操作系统内进行设置。我在这里是扩成80GB。
(2)在终端使用命令
sudo apt-get install Gparted
下载Gparted部件。
(3)打开Gparted:
(4)打开Gparted应用,你可以看到已分配分区状况和新增未分配的分区 :
(5)然后依次删除/dev/sda5和/dev/sda2,删除后,就会剩下/dev/sda1(14GB)和未分配的(15GB),不然的话你怎么都无法将unallocated部分挂载。
(6)接下来重新调整/dev/sda1的大小,我这里调整为75529MiB(73.76GB),然后剩下6.24GB作为linux_swap,重新将未分配的6.24GB格式化,先new出一个extended的分区,然后再在这个extended的分区里new一个逻辑分区,并且file system选择为linux-swap,最后选择绿色的钩钩,完成保存。最后执行完后,如下图所示:
(7)这样我就把虚拟机的硬盘扩成了80GB,编译内核源码绝对是绰绰有余的了。
(注:本小节参考了博客:http://blog.csdn.net/Timsley/article/details/50742755)
2、构建内核源码树
(1)我的虚拟机的操作系统是ubuntu16.04。我是在这里下载的源码包:https://www.kernel.org/pub/linux/kernel/v4.x/,我下载的源码包是linux-4.10.14.tar.xz
附:大家千万不要在非www.kernel.org开头的网站上随意下载内核源码!
(2)下载完之后解压即可:
3、编译内核
(1)安装基本的工具软件。
逐次在终端执行以下四条命令:
sudo apt-get install libncurses5-dev libssl-dev
sudo apt-get install build-essential openssl
sudo apt-get install zlibc minizip
sudo apt-get install libidn11-dev libidn11
(2)在终端进入你的解压的内核源码的目录,比如我内核源码解压后在home/expr/expr4/linux-4.10.14,那么进入终端后就是:
(3)依次执行以下三条命令:
sudo make mrproper
sudo make clean
sudo make menuconfig
其中mrproper为清除编译过程中产生的所有中间文件,clean为清除上一次产生的编译中间文件,在menuconfig中出现选择的图形化界面后,直接按右方向键选择到exit退出,退出提示中选择保存,实现内核的默认配置。
(4)执行命令:
sudo make –j8
因为我的笔记本cpu是i7四核八线程,所以我直接用8个线程并行编译,这样编译速度就是普通的make命令的8倍。最近双一流建设学校发了财换了一大批新电脑,所以在我学校的高性能计算实验室编译内核,因为处理器是新买的intel core i7 6700k,8线程编译的话20分钟就搞定了,普通笔记本应该要1~2小时。
下面放一波编译的时候截的图:
正在编译内核
编译的时候监测笔记本状态,怕内存泄漏
(5)依次执行命令:
sudo make modules_install //安装内核模块
sudo make install //安装内核
下面放一波编译的时候截的图:
正在执行sudo make modules_install
正在执行sudo make modules_install
正在执行sudo make install
新内核成功嵌入操作系统
(6)重新启动系统,如果是虚拟机的话记得重启进入BIOS界面之前一定要点击鼠标进入虚拟机的界面实现键盘捕获。在重启开机界面按住shift键不放手,选择高级选项,进入内核选择加载界面,选择自己编译的内核的正常模式:
进入内核选择模式,选择自己编译的内核:
(7)至此,工作完成了50%。随着操作系统的启动,我新编译的内核也正式诞生了!
(注:本小节参考了博客:http://blog.csdn.net/Xiaobai__Lee/article/details/72048829)
4、写自己的设备驱动程序
(1)写在前面:
在编程的时候,不要轻易复制任何网站的代码,99.99%都是跑不通的。Makefile文件尤其不要随便在网上下载,因为这个东西对格式要求非常高,新手随便在网上下的Makefile文件也是99.99%都是跑不通。要跑通,有两个关键:1、认真分析每一条源代码;2、有问题,多去搜一下看看。
(2)我在ubuntu下编写的代码如下:
(3)要在内核态下编译我们写好的设备驱动程序源码,必须使用Makefile文件。
Makefile文件内容截图,每个关键字都出现彩色的时候说明基本上没写错
(4)在终端下进入设备驱动程序源码所在的文件夹,例如,我的源码放在home/expr/expr4/expr4/code/,那么就是这样:
(5)输入make命令,之后在文件夹下直接生成.ko文件:
(6)继续在终端下输入命令:sudo insmod globalmem.ko将刚刚生成的globalmem.ko文件加载进入内核。
(7)用命令lsmod查看是否加载成功,如果成功就是这样:
可以看到第一个module就是我刚刚生成的globalmem。
(8)到这里工作完成了85%。可以先不急着去写测试程序,可以先用原语测试一下驱动,因为我的这个驱动是处理字符的驱动程序,所以我是这样测试的:
也就是进入root模式后用原语将字符串“tz”送入驱动,驱动就会输出“tz”。
(9)现在就可以踏踏实实地去写测试程序了:
(10)编译这个C程序,并运行:
测试程序运行正常,表明设备驱动运行正常。
至此,我的教程就结束了。有疑问的朋友可以直接在评论区留言,非常希望和各位朋友一起讨论!
TZ@华中农业大学信息学院高性能计算实验室
2017/12/12夜