嵌入式|嵌入式linux系统交叉编译内核驱动模块笔记,以一个完全的新手姿势记录

序言 【嵌入式|嵌入式linux系统交叉编译内核驱动模块笔记,以一个完全的新手姿势记录】最近终于成功的在自己的手中将一个hello的内核模块成功的编译并加载进自己的嵌入式linux系统,教程翻了无数篇,果然理论的了解和实际上的知道怎么做之间,还存在着很大的差距。。鉴于在查找资料中看到不少的教程中都存在着部分知识缺失的问题,总的来说就是:“我觉得某些东西太过简单我没有必要再讲”,而这一部分又直接导致我一个萌新给完全的给看懵了,因此在这里写一下自己的笔记,着重讲一些当时自己走了弯路的地方。
准备工作 为了能够交叉编译内核驱动,首先你需要:

  • 你的对应的硬件平台的内核源码
  • 对应硬件平台的交叉编译器
获取到了这两个工具之后还需要进行配置才可以使用。。
交叉编译器 将交叉编译器放在一个确切的位置,随后在进行工作前需要将它添加到环境变量(可以使用export单独导出,也可以编辑一个setting.sh每次工作前运行一下,甚至可以添加到~/.bashrc中每次启动终端时自动设定)。如果不添加环境变量的话则需要在每次make指令后面都手动加上编译器参数和架构参数。常见的配置参数如下,根据自己具体需要进行修改:
#!/usr/bin/bash export ARCH=arm export CROSS_COMPILE=arm-linux-

内核的编译 要想成功的进行驱动的编译,首先需要有一个成功编译过的内核源码。所以我们需要先进行内核的编译。一般内核需要先通过make menuconfig生成内核的编译配置选项。在没有特定需求的时候我们只需要保存退出即可。完成内核的编译配置选项后就可以使用make进行编译了。注意:使用make之前必须确保架构和交叉编译器的参数都已在环境变量中!
驱动编写 接下来到这一步才是正式开始驱动的编译。我们的第一个测试用的驱动,仅仅实现加载和卸载时对内核的消息日志输出。驱动工程的文件夹可以在源码树下,也可以在源码树外的自定义目录,在这里我将驱动工程文件夹放在了源码树外的目录,其文件信息如下:
hello.c
#include #include static int hello_init(void) { printk("Hello kernel world!\n"); return 0; }static void hello_exit(void) { printk("Goodbye world!\n"); }module_init(hello_init); module_exit(hello_exit); MODULE_AUTHOR("982670455@qq.com>"); MODULE_LICENSE("Dual BSD/GPL");

在内核的编译中,因为不是输出为普通的可执行程序而是输出为内核模块,因此需要独立编写Makefile文件,也建议在进行驱动学习的时候要了解Makefile的简单原理。
Makefile
obj-m:=hello.o

这里是一个最简单没有任何其他功能的Makefile,目的就是把hello.c编译成可加载模块hello.ko文件,当读者进一步了解Makefile机制的时候可以选择添加更多的功能,比如清理等。
驱动编译
在完成以上工程文件后,我们就可以使用这个最简单的Makefile来编译文件了。但是由于编译驱动需要根据内核的源码树进行操作,因此我们在编译的指令中还需要加入内核源码树的目录,然后还要指定编译为模块,最终编译指令如下:
make -C /media/wmd/a1f4b143-42e4-413c-8c1e-bacea116f841/kernel-src/linux-nanopineo/ M=`pwd`modules

其中-C后面跟着的就是内核的源码(已经编译过的),而M=则为我们的新模块的目录,由于我们在当前目录下,所以使用内嵌命令pwd即可得到,最后一个参数modules指定编译为模块。
编译完成后可以看到工作目录下会得到hello.ko文件和其他相关文件。
嵌入式|嵌入式linux系统交叉编译内核驱动模块笔记,以一个完全的新手姿势记录
文章图片

驱动加载
到了这一步 其实已经很简单了,将编译好的内核模块传输到目标机上,随后在目标机上使用sudo insmod hello.ko指令来添加模块。添加完成后可以使用lsmod来查看模块。使用rmmod来进行模块的卸载。由于模块除了内核打印日志外没有任何响应,我们可以通过查看内核日志dmesg的方法来查看内核是否正常工作。
嵌入式|嵌入式linux系统交叉编译内核驱动模块笔记,以一个完全的新手姿势记录
文章图片

最终我们可以看到驱动的日志被正常的打印,也就是我们的驱动可以正常的工作!

    推荐阅读