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 @   thammer  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示