Linux为使用程序供给了弱小且可扩大的API,但有时那其实不够。在系统中和硬件交互或者履行需求拜访失密信息的操作时需求一个中心模块。
Linux内核是一组编译后的二进制码,它可以直接嵌入 Linux内核,在Ring0上运转,是在x86 - 64处置器中履行的最低和最小维护环。这里的代码完整不受把持,但运转速度惊人并且可以拜访系统中的一切内容。
编写Linux内核不合适胆怯鬼。更改内核,您将可能面对数据丧失和系统破坏的风险。内核编码没有平常的Linux使用程序所习气的安全保证。假如你有一个错误,他将锁定全部系统。
更蹩脚的是,你的问题可能不会浮现出来。运转失败的最好的情况是模块在加载是立即被锁定。当您向模块中添加更多代码时,您就面对这轮回时空和内存走漏的风险。假如你不细心,这些风险将跟着机械运转而不断增加。终极,主要的内存构造乃至缓冲区都可能被掩盖。
传统的使用程序开发形式将要被大量抛弃。除模块的加载和卸载以外,您还将编写系统呼应事情而不是履行次序形式运转的代码。跟着内核的开展,你将要编写的是APIs,而不是使用程序自身。
您还没有拜访规范库的权限。而内核供给的一些功用如printk(作为一种printf的替换)和kmalloc(其任务方法相似于malloc),大部分都由你本人决议。别的,当你的模块被卸载时,您要担任将您本人的模块清算洁净。这没有渣滓收受接管机制。
在我们Start之前,要确保用的是准确的任务Tools。更主要的是,你需求一台Linux系统的机械。我晓得那完整是一个不测!固然恣意的Linux的版本都可以,在例子中我将要运用Ubuntu 16.04 LTS,假如您运用其他的版本,可能需求略微调剂安装号令。
其次,您需求一个自力的运转情况或者虚拟机。我更倾向在虚拟机中任务,但这完整取决于您。我不建议您运用您以后的机械,由于当你呈现错误时数据可能会丧失。我是说甚么时分,而不是假如,由于在这个过程当中你一定会锁定您的机械几回。当内核极端忙碌的时分,你的最新代码会寄存在缓冲区,因而,您的源文件可能会破坏。而在虚拟机中实行这类测试可以消弭这类风险。
最初,你需求晓得一点C的常识。C++运转库内核太大,所以写裸机的C是必不成少的。为了与硬件实行交互。了解一些程序集可能会有所协助。
在 Ubuntu 中我们需求运转:
apt-get install build-essential linux-headers-`uname -r`
这个号令会安装本示例所需求的开发Tools和中心头文件。
下面的示例假定你是一个通俗用户而不是 root 用户,可是你有 sudo 权限。sudo 是用于加载中心模子的,但我们盼望尽量地不运用 root 用户。
我们Start写代码之前,先预备情况:
mkdir ~/src/lkm_example cd ~/src/lkm_example
翻开你爱好的编辑器(我运用 VIM),创立文件 lkm_example.c,输出下面的内容:
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h>
MODULE_LICENSE(“GPL”); MODULE_AUTHOR(“Robert W. Oliver II”); MODULE_DESCRIPTION(“A *** example Linux module.”); MODULE_VERSION(“0.01”);
static int __init lkm_example_init(void) { printk(KERN_INFO “Hello, World! ”); return 0; }
static void __exit lkm_example_exit(void) { printk(KERN_INFO “Goodbye, World! ”); }
module_init(lkm_example_init); module_exit(lkm_example_exit);
我们曾经结构了一个极尽容易的模块,如今我们举例来具体说明各个主要部分:
“includes” 涵盖了 Linux 内核开发所需求的头文件。
MODULE_LICENSE 可用于设置表现模块答应的值。假如想晓得完好的答应列表,可以运转: grep “MODULE_LICENSE” -B 27 /usr/src/linux-headers-`uname -r`/include/linux/module.h
我们定义了静态的初始化(加载)和加入(卸载)函数,它们都前往整数。
留意我们用的 printk 而不是 printf。printk 与 printf 的参数有所分歧。比方 KERN_INFO 声了然以后Log行的优先级,声明中没有运用逗号。内核在 printk 外部收拾这些值以节俭栈空间。
在文件的最初,我们挪用 module_init 和 module_exit 来通知内核哪一个是加载函数,哪一个是卸载函数。如许我们可以按本人爱好对函数自在定名。
可是我们还不能编译这个文件。我们需求制作一个文件。这个根底实例如今要起用处了。留意,make关于空格键和 tab 键长短常刻薄的,所以要包管的恰当的地方用 tabs 键替代 Tab 键。
obj-m += lkm_example.o
all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
当你运转"make"时,它应当可以成功的编译你的模块。这个文件的编译后果是“lkm_example.ko”。假如你发明任何错误,请check你的示例文件中的援用是不是是准确的,而且check是否不警惕粘贴了UTF-8的字符。
如今我们来添加这个模块实行测试。运转操作:
sudo insmod lkm_example.ko
假如运转成功,你还看不就任何后果。printk 函数不会输出在把持台而是输出在内核Log。为了看到Log,我们运转一下号令:
sudo dmesg
你将会看到“Hello,World!”前边有一个时间戳。这意味着内核模块加载并成功的将后果打印在内核Log。我们还可以check模块是不是依然被加载:
lsmod | grep “lkm_example”
要想移除该模块,运转一下号令:
sudo rmmod lkm_example
假如你再一次运转dmesg,你将会在Log中看到“Goodbye,World!”。你可以再一次运转lsmod来确认模块是不是已卸载。
其它翻译版本 (1) 加载中正如你所看到,这个测试任务流程有点有趣,为了让其实行主动化测试,在Makefile开头添加以下代码:
test: sudo dmesg -C sudo insmod lkm_example.ko sudo rmmod lkm_example.ko dmesg
然后运转以下号令:
make test
不用再运转单行号令来测试我们的模块和在内核Log看输出。
如今我们有了一个功用全面但又十分琐碎的内核模块!
本文中的一切译文仅用于进修和交换目标,转载请务必注明文章译者、出处、和本文链接。 2KB翻译任务按照 CC 协议,假如我们的任务有进犯到您的权益,请实时联络我们。2KB项目(www.2kb.com,源码交易平台),供给担保交易、源码交易、虚拟商品、在家创业、在线创业、Task交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接生意、网站交易、广告生意、站长培训、建站美工等服务