目录
6、使用以下命令将生成的uImage内核镜像文件拷贝到tftp的工作目录下
新功能源码与Linux内核源码在同一个目录结构下(大部分配置流程和静态加载时类似)
向Linux内核添加新功能的静态加载与动态加载
开发环境:
Ubuntu18.04
在进行linux驱动开发时,当我们想要向linux内核添加一些新功能时,一般可以采用静态加载和动态加载的方法。以下简要介绍下这两种不同的加载方式及一般流程。
一、静态加载法
所谓静态加载法,即将新功能的源码与内核其它代码一起编译进uImage内核镜像文件内。
内核源码顶层目录:/home/ubuntu/linux-3.14 新功能源码文件名:myhello.c 新功能源码路径和linux内核字符设备驱动的路径:/home/ubuntu/linux-3.14/drivers/char/
1、新功能源码与Linux内核源码在同一个目录结构下
myhello.c文件内容如下:
#include <linux/module.h>
#include <linux/kernel.h>
int __init myhello_init(void)
{
printk("#####################################################\n");
printk("#####################################################\n");
printk("#####################################################\n");
printk("#####################################################\n");
printk("myhello is running\n");
printk("#####################################################\n");
printk("#####################################################\n");
printk("#####################################################\n");
printk("#####################################################\n");
return 0;
}
void __exit myhello_exit(void)
{
printk("myhello will exit\n");
}
MODULE_LICENSE("GPL");
module_init(myhello_init);
module_exit(myhello_exit);
2、给新功能代码配置Kconfig
#进入myhello.c所在目录
cd ~/linux-3.14/drivers/char
vim Kconfig
在配置文件中添加如下内容:
config MY_HELLO
tristate "This is a hello test"
help
This is a test for kernel new function
3、给新功能代码改写Makefile
#进入myhello.c所在目录
cd ~/linux-3.14/drivers/char
vim Makefile
#使用obj指定要编译的对应的.o文件(前面的源文件是.c文件,这里是.c文件所对应的.o文件)
obj-$(CONFIG_MY_HELLO) += myhello.o
4、使用make menuconfig 在配置界面里将新功能对应的那项选择成<*>
cd ~/linux-3.14
make menuconfig
注意: 如果使用make menuconfig时出错,一般是以下两个原因: 1. libncurses5-dev没有安装 可以使用以下命令进行安装:
sudo apt-get update
sudo apt-get install libncurses5-dev
2. 命令行界面太小(太矮或太窄或字体太大了)
首先、在界面下找到Device Drivers(设备驱动)。如下图所示:
然后、找到Character devices(字符设备驱动)。如下图所示:
接着、可以找到我们之前添加的源文件myhello.c的配置信息。在对应的配置项前面设置为<*>,如下图所示:
最后,使用左右键选择Exit一步一步的退出,出现如下界面时选择Yes保存配置即可。
5、使用以下指令重新编译内核
make uImage(这里需要提前配置好所使用的交叉编译器,编译出在ARM平台使用的内核镜像文件)
6、使用以下命令将生成的uImage内核镜像文件拷贝到tftp的工作目录下
使用以下命令将生成的uImage内核镜像文件拷贝到tftp的工作目录下,我这里是/tftpboot。
cp arch/arm/boot/uImage /tftpboot
7、启动开发板观察串口终端中的打印信息即可
如下图所示,可以看到我们之前程序源码中的打印信息。这就说明我们向内核中新添加的功能正常运行了。
二、动态加载法
所谓动态加载法,即新功能源码与内核其它源码不一起编译,而是独立编译成内核的插件(被称为内核模块)文件.ko。
动态加载法又可以分为两种情况: 1、新功能源码与Linux内核源码在同一个目录结构下。 2、新功能源码与Linux内核源码不在同一个目录结构下。
新功能源码与Linux内核源码在同一个目录结构下(大部分配置流程和静态加载时类似)
1. 给新功能源码配置Kconfig
2. 给新功能代码改写Makefile,Makefile文件如下:
#======================================================================
ifeq ($(KERNELRELEASE),)
ifeq ($(ARCH),arm)
KERNELDIR ?= linux内核源码顶层目录的绝对路径
ROOTFS ?= 网络文件系统顶层目录的绝对路径
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_install
clean:
rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versions
else
obj-m += myhello.o
endif
#注意:
#Makefile里如果没有配置交叉编译工具链,可以在~/.bashrc中进行配置,或者使用export等命令临时配置。
#obj-m用来指定模块名,注意模块名加.o而不是.ko。
#一个目录下的Makefile可以编译多个模块:
#添加:obj-m += 下一个模块名.o
#======================================================================
3. 使用make menuconfig,在配置界面里将新功能对应的那项选择成<M>
4. 使用make uImage重新编译内核
5. 将生成的uImage内核镜像文件拷贝到tftp的工作目录下
cp arch/arm/boot/uImage /tftpboot
6. 使用make modules命令重新编译内核模块(注意此命令执行前,要保证开发板的内核源码已经被编译)
make modules命令会在新功能源码的同级目录下生成相应的同名.ko文件
新功能源码与Linux内核源码不在同一目录结构下
内核源码顶层目录:/home/ubuntu/linux-3.14 新功能源码文件名:myhello.c linux内核字符设备驱动的路径:/home/ubuntu/linux-3.14/drivers/char/ 新功能源码路径:/home/ubuntu/mydrivercode
1. cd ~
2. mkdir mydrivercode
3. cd mydrivercode
4. cp ~/linux-3.14/drivers/char/myhello.c . //拷贝之前的myhello测试程序源码
5. vim Makefile
6. make ARCH=arm (生成的ko文件适用于linux开发板,注意此命令执行前,开发板的内核源码已被编译)
注意:
1、Makefile里如果没有配置交叉编译工具链,可以在~/.bashrc中进行配置,或者使用export等命令临时配置。
2、使用file命令可以查看编译出的ko文件适用于哪种平台,用法:
file ko文件
输出结果带x86字样的适用于主机ubuntu,带ARM字样的适用于ARM linux开发板。
7、在ARM开发板下加载驱动模块 7.1首先将生成的.ko文件拷贝到网络文件系统nfs的工作目录下
cp xxx/xxx.ko 网络文件系统nfs的工作目录
7.2然后在开发板上使用mount命令挂载ubuntu主机上的网络文件系统 7.3接着使用mobaxterm等软件采用串口连接的方式连接开发板的串口,在其终端下输入:
insmod ./xxx.ko #将内核模块插入正在执行的内核中运行 ----- 相当于安装插件
lsmod #查看已被插入的内核模块有哪些
rmmod xxx #将已被插入的内核模块从内核中移除 ----- 相当于卸载插件
内核随时打印信息,我们可以在串口终端界面看到打印信息。
完结。。。