linux内核和内核模块的区别,Kernel Module实战指南(二):内核模块和应用程序的区别...

Introduction

你已经写出了第一个内核模块Hello World!有没有发现内核模块和应用程序写法的不同?

下面我将从概念和原理上进行介绍,内核模块和应用程序为什么不同。

内核模块和应用程序的区别

出入口

应用程序的入口始终是main()函数,而出口是main()函数的return。

内核模块的入口是init_module(),而出口是cleanup_module()。

函数库

应用程序可以调用很多C标准库中的函数,如printf()。这些函数都编译到libc中,只有当你的代码在编译的链接阶段时,才会和libc中实际的函数地址绑定。

内核模块则不同,内核中不存在标准库,自然没有类似printf()之类的函数。不过内核中提供了一些函数/符号,你可以通过下面的命令查看:

$ cat /proc/kallsyms | grep printk

...

0000000000000000 T printk

0000000000000000 T printk_emit

...

所有内核中可以用的函数/符号都在/proc/kallsyms,换句话说,你不能使用这里之外的函数/符号。

CPU执行模式

在Intel x86架构上中,有四种模式,也叫ring 0 - ring 3,模式之间的权限不同,这里的权限指的是对硬件设备的操作,如读写内存,读写硬盘等。

Linux使用其中两种模式,即内核模式/特权模式/supervisor mode/ring 0,以及用户模式/非特权模式/user mode/ring 3。

应用程序跑的代码,包括所调用的C标准库,都是跑在用户模式中。而内核模块跑的代码,都是跑在内核模式中。用户模式想要进入内核模式,入口之一便是系统调用函数。

用户态和内核态之间的交互

用户态和内核态进行交互的方式之一,是上面我们提到过系统调用函数。什么是系统调用函数?你可以简单认为,libc调用的下层函数,就是系统调用函数,如libc中open()的实现,最终需要调用系统调用函数__NR_open(),进入内核,在内核态中访问硬盘,打开文件。

另一种方式是设备驱动程序,Linux的设备驱动都存放在/dev下面,当用户态程序和设备驱动交互时,设备驱动在内核态执行代码逻辑,然后将结果返回给用户态。

设备驱动

查看硬盘驱动:

$ls -l /dev/sda*

brw-rw---- 1 root disk 8, 0 Jan 26 23:00 /dev/sda

brw-rw---- 1 root disk 8, 1 Jan 26 23:00 /dev/sda1

brw-rw---- 1 root disk 8, 2 Jan 26 23:00 /dev/sda2

brw-rw---- 1 root disk 8, 3 Jan 26 23:00 /dev/sda3

如果你找不到sda,那么你可以查询ls -l /dev/hda*。

这里需要简单介绍一下,列的含义。第一列的b,是block的意思,代码这个设备是块设备(对应的是c, char字符设备)。

块设备:存储单位一般是固定大小的块,支持随机读写。对于读写请求有缓存,可以选择最佳的位置存储。(有没有想到硬盘的寻址算法?)

字符设备:存储大小不定,存储流式数据,一般不支持随机读写,只支持顺序读写。

8的意思是,驱动的主版本号是8,这个主版本号是给内核看的。

后面的0-3的意思是,副版本号是0-3,这个副版本号是给设备驱动程序看的,内核不关心。

这里只是抛砖迎玉,后面我们再详细介绍设备驱动。

Summary

我们进一步深入了内核模块,介绍了内核模块和应用程序的区别。虽然概念性内容偏多,但这却是理解内核模块的必经之路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值