00-一个helloworld级别的内核模块

本文针对嵌入式设备

0.准备工作

  • 安装并配置好交叉编译工具链
  • 交叉编译linux内核,为编译内核模块提供编译环境

1.内核模块的入口和出口

linux内核提供了一对注册宏module_init(initfn)module_exit(exitfn),它俩用于向内核注入内核模块的入口函数和出口函数。分别对应的声明为:

int init_module(void);
void cleanup_module(void);
  • 入口函数在模块加载时做一些初始化动作,出口函数在模块卸载时做一些清理动作。

完整示例为:

#include <linux/module.h>

//加载内核模块后的入口函数
static int __init simplest_drv_init(void)
{
    printk(KERN_INFO "Simplest driver init\n");
    return 0;
}

//卸载内核模块后的清理函数
static void __exit simplest_drv_exit(void)
{
    printk(KERN_INFO "Simplest driver exit\n");
}

module_init(simplest_drv_init);
module_exit(simplest_drv_exit);
  • 内核模块里面的函数如果不需要导出给外部使用(使用EXPORT_SYMBOL宏来实现),通常声明为static,主要是为了避免符号冲突,起到隔离作用。
  • __init__exit是一个编译器扩展标志的宏,内核源码里面注释了它的作用:标记函数或者初始化的变量(不要对未初始化的数据使用),在初始化动作完成后释放相关内存资源。

2.外部模块的Makefile

需要一个Makefile来方便编译:

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
KERN_DIR=/mnt/2Thdd/wds/100ask_imx6ull-sdk/Linux-4.9.88/

obj-m += simplest_drv.o

all:
	make -C ${KERN_DIR} M=$(shell pwd) modules

clean:
	make -C ${KERN_DIR}  M=$(shell pwd) clean

嗯,没错我用的是韦东山的imx6ull pro开发板,9年前入门也是看他的2440视频,但是后面因为工作原因去搞应用开发了。

makefile稍微解释下:

  • 开头的两个export是指shell里面导出环境变量,kernel里面的Makefile会推导使用它们,好奇的可以看看。
  • obj-m += simplest_drv.o,内核编译框架下指定将当前文件下的simplest_drv.c(makefile的自动推导,由.o推导出.c)编译为内核模块。还有一个是obj-y表示直接编译进内核,这里不发散。
  • ‘-C’进到指定目录执行make命令,这里就是内核编译目录。
  • 后面的M=xxx是内核编译框架下指定要编译的外部内核模块的源码目录,modulesclean是makefile的两个目标而已。

以下是拷贝自内核顶层Makefile里面针对外部模块的注释

###          
# External module support.
# When building external modules the kernel used as basis is considered
# read-only, and no consistency checks are made and the make
# system is not used on the basis kernel. If updates are required
# in the basis kernel ordinary make commands (without M=...) must
# be used.   
#            
# The following are the only valid targets when building external
# modules.   
# make M=dir clean     Delete all automatically generated files
# make M=dir modules   Make all modules in specified dir
# make M=dir           Same as 'make M=dir modules'
# make M=dir modules_install
#                      Install the modules built in the module directory
#                      Assumes install directory is already created

3.编译并测试

加载内核模块通过insmod命令,卸载通过rmmod,查看当前已加载的内核模块则通过lsmod
通过scp把编译出来的simplest_drv.ko搞进开发板,并加载模块,然后查看:

[root@100ask:~]# insmod simplest_drv.ko 
[43988.862630] Simplest driver init
[root@100ask:~]# lsmod 
Module                  Size  Used by
simplest_drv             991  0
[root@100ask:~]# rmmod simplest_drv.ko 
[43994.023260] Simplest driver exit
[root@100ask:~]# lsmod 
Module                  Size  Used by

insmod会导致sysfs的挂载目录sys下的module里面新增一个目录:

[root@100ask:/sys/module]# ls -d simplest_drv 
simplest_drv

这个内核模块啥都没干,就是注册并跑了下入口函数和出口函数,所谓hello world级别。

posted @ 2024-09-26 18:55  thammer  阅读(11)  评论(0编辑  收藏  举报