Linux驱动开发入门与hello驱动开发介绍
创始人
2025-05-29 21:57:14

文章目录

    • 1- Linux内核介绍
    • 2- 编写hello模块c文件
      • (1)Linux下编译运行
      • (2)imx6ull开发板运行


首先弄懂linux驱动的相关信息,然后介绍最简单的内核模块,让大家了解内核模块的编写、编译和使用。

1- Linux内核介绍

现在我们从一个比较高的高度来审视一下GNU/Linux操作系统的体系结构。如下图所示,最上面是用户(或应用程序)空间,这是用户应用程序执行的地方。用户空间之下是内核空间,Linux内核正是位于这里。C基础库(如glibc, eglibc, uclibc等)也属于应用程序空间,它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。

Linux 内核可以进一步划分成 3 层。最上面是系统调用接口(SCI,System Call Interface),它实现了一些基本的功能,例如 open()、read()、write()、close()等。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码、这些代码是 Linux 所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board SupportPackage)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。

在这里插入图片描述
Linux内核实现了很多重要的体系结构属性。在或高或低的层次上,内核被划分为多个子系统。Linux也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。每种内核都有自己的优点,不过这里并不对此进行讨论。随着时间的流逝,Linux内核在内存和 CPU 使用方面具有较高的效率,并且非常稳定。但是对于 Linux 来说,最为有趣的是在这种大小和复杂性的前提下,依然具有良好的可移植性。

在这里插入图片描述

系统调用接口

SCI 层提供了某些机制执行从用户空间到内核的函数调用。正如前面讨论的一样,这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。
在应用层空间调用了系统调用,是在内核空间中运行了。我们可以time来看一下两个空间的运行时间:

wangdengtao@wangdengtao-virtual-machine:~$ time ping 4.2.2.2 -c 4
PING 4.2.2.2 (4.2.2.2) 56(84) bytes of data.
64 bytes from 4.2.2.2: icmp_seq=1 ttl=53 time=314 ms
64 bytes from 4.2.2.2: icmp_seq=2 ttl=53 time=297 ms
64 bytes from 4.2.2.2: icmp_seq=3 ttl=53 time=305 ms
64 bytes from 4.2.2.2: icmp_seq=4 ttl=53 time=287 ms--- 4.2.2.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3024ms
rtt min/avg/max/mdev = 287.472/300.647/313.502/9.614 msreal	0m3.287s//实际运行的时间
user	0m0.002s//用户空间运行的时间
sys	    0m0.000s//内核空间运行的时间

内存管理

内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页方式进行管理的(对于大部分体系结构来说都是4KB)。Linux包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。不过内存管理要管理的可不止4KB缓冲区。Linux提供了对4KB缓冲区的抽象,例如slab分配器。这种内存管理模式使用4KB缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空,这样就允许该模式根据系统需要来动态调整内存使用。为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上, Linux系统中,被用于交换的分区叫swap分区,在windows系统下叫做虚拟内存。

文件系统

虚拟文件系统(VFS)是Linux内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS在SCI和内核所支持的文件系统之间提供了一个交换层。在VFS上面,是对诸如open,close, read 和 write之类的函数的一个通用API抽象,在 VFS下面是文件系统抽象,它定义了上层函数的实现方式。
可以理解为有了文件系统只有我们对硬盘的操作操作路径就可以了。如果没有文件系统就没有路径的概念了。

网络管理
网络堆栈在设计上遵循模拟协议本身的分层体系结构。回想一下, Internet Protocol (IP)是传输协议(通常称为传输控制协议或TCP)下面的核心网络层协议,TCP上面是socket层,它是通过SCI进行调用的。socket是网络子系统的标准API。它为各种网络协议提供了一个用户接口,从原始帧访问到IP协议数据单元( PDU) ,再到TCP和User Datagram Protocol (UDP) , socket层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。

设备管理(驱动程序)
Linux内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如 Bluetooth,l2C,serial 等,设备驱动程序的代码可以在/linux/drivers中找到。


2- 编写hello模块c文件

直接上代码(代码中注释解释的听清楚的,可以仔细看看):

#include 
#include 
#include /*定义了个名为 xxx_init 的驱动入口函数,并且使用了“__init”来修饰.*/
static __init int hello_init(void)
{/*在 Linux 内核中没有 printf 这个函数。printk 相当于 printf 的孪生兄妹,printf运行在用户态,printk运行在内核态。*/printk(KERN_ALERT "Hello world\n");return 0;
}/*定义了个名为 xxx_exit 的驱动出口函数,并且使用了“__exit”来修饰.*/
static __exit void hello_exit(void)
{printk(KERN_ALERT "Goodbye world\n");
}
/*
module_init函数用来向 Linux内核注册一个模块加载函数,参数 xxx_init就是需要注册的具体函数,当使
用“ insmod”命令加载驱动的时候 xxx_init这个函数就会被调 用。 module_exit()函数用来向 Linux内核
注册一个模块卸载函数,参数 xxx_exit就是需要注册的具体函数,当使用“ rmmod”命令卸载具体驱动的时
候 xxx_exit函数就会被调用。所以一般在xxx_init函数里进行一些驱动的初始化工作,在xxx_exit里面就
需要对驱动程序的卸载做一些回收工作。
*/
/*调用函数 module_init 来声明 xxx_init 为驱动入口函数,当加载驱动的时候 xxx_init函数就会被调用.*/
module_init(hello_init);
/*调用函数module_exit来声明xxx_exit为驱动出口函数,当卸载驱动的时候xxx_exit函数就会被调用.*/
module_exit(hello_exit);/*添加LICENSE和作者信息,是来告诉内核,该模块带有一个自由许可证;没有这样的说明,在加载模块的时内核会“抱怨”.*/
MODULE_LICENSE("Dual BSD/GPL");//许可 GPL、GPL v2、Dual MPL/GPL、Proprietary(专有)等,没有内核会提示.
MODULE_AUTHOR("WangDengtao");//作者
MODULE_VERSION("V1.0");//版本

(1)Linux下编译运行

Makefile:

KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
obj-m := hello.oall:$(MAKE) -C $(KERNAL_DIR) M=$(PWD) modulesclean:@rm -f *.o *.cmd *.mod *.mod.c@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f@rm -f .*ko.cmd .*.o.cmd .*.o.d@rm -f *.unsigned@rm -f *.ko

然后执行make:
在这里插入图片描述
警告
这里出现了警告,主要是gcc版本不匹配,应该不影响吧,继续操作。
可以看见我们的文件夹中多了很多文件,至于其他的文件,不要紧,最主要的看hello.ko文件。

wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver$ ls
hello.c  hello.ko  hello.mod  hello.mod.c  hello.mod.o  hello.o  Makefile  modules.order  Module.symvers

我们可以看见hello.ko文件。我们可以使用insmod和rmmod命令加载或者卸载驱动。

wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver$ sudo insmod hello.ko
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver$ sudo rmmod hello
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver$ sudo insmod hello.ko
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver$ dmesg | tail -3
dmesg: 读取内核缓冲区失败: 不允许的操作
wangdengtao@wangdengtao-virtual-machine:~/wangdengtao/driver$ sudo dmesg | tail -3
[ 8577.201090] Hello world
[ 8580.442205] Goodbye world
[ 8582.097892] Hello world

用lsmod命令查看当前linux内核安装了的内核模块:
在这里插入图片描述

(2)imx6ull开发板运行

首先需要在linux上安装内核源码树的目录,也就是arm架构的。这个就需要根据开发板自身需求去安装了。
Makefile:

KERNAL_DIR ?= /home/wangdengtao/imx6ull/imx6ull/bsp/kernel/linux-imx
PWD :=$(shell pwd)
obj-m := hello.oall:$(MAKE) -C $(KERNAL_DIR) M=$(PWD) modulesclean:@rm -f *.o *.cmd *.mod *.mod.c@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f@rm -f .*ko.cmd .*.o.cmd .*.o.d@rm -f *.unsigned@rm -f *.ko

将hello.ko文件移动到tftpboot目录下,方便开发板能够tftp获取到。

开发板获取到了我们就加载和卸载驱动来测试一下:

cp hello.ko /home/wangdengtao/wangdengtao/tftpboot/
root@igkboard:~# tftp -gr hello.ko 192.168.10.168
root@igkboard:~# ls
hello.koroot@igkboard:~# insmod hello.ko                
root@igkboard:~# dmesg | tail -1
[  820.486004] Hello worldroot@igkboard:~# lsmod 
Module                  Size  Used by
hello                  16384  0
rtl8188fu             999424  0
imx_rngc               16384  0
rng_core               20480  1 imx_rngc
secvio                 16384  0
error                  20480  1 secvioroot@igkboard:~# rmmod hello.ko 
root@igkboard:~# dmesg | tail -1
[  861.499208] Goodbye world

测试成功。


相关内容

热门资讯

应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
cad打印线条粗细设置 cad... 004-线型(下)打印样式设置和线型文件使用一、线宽设置方法制图规范里边的线宽要求,我们已经定义好,...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
荼蘼什么意思 岁月缱绻葳蕤生香... 感谢作者【辰夕】的原创独家授权分享编辑整理:【多肉植物百科】百科君坐标:云南 曲靖春而至,季节流转,...