IMX6LL|内核模块

内核模块基本概念

作用

解决linux内核可扩展性和可维护性相对较差的缺陷

现代内核派系

宏内核:关键功能和服务功能均在内核空间提供

  • 运行效率高
  • 扩展性较差

微内核:内核空间只提供关键功能,服务功能在用户空间提供

  • 运行效率较低
  • 安全性、扩展性较高
内核模块加载/卸载
  • 使用insmod命令加载

  • 使用rmmod命令卸载

内核模块入口/出口
  • module_init():加载模块式该函数自动执行,进行初始化操作
  • module_exit():卸载模块时函数自动执行,进行清理操作
内核模块信息声明
  • MODULE_LICENSE():表示模块代码接受的软件许可协议,Linux内核遵循GPL V2开源协议,内核模块与linux内核保持一致即可。
  • MODULE_AUTHOR():描述模块的作者信息
  • MODULE_DESCRIPTION():对模块的简单介绍
  • MODULE_ALIAS():给模块设置一个别名

内核模块实验1

实验环境
  • 开发板烧录好Debian镜像
  • 启动开发板,搭建好nfs客户端,挂载共享文件夹
  • 获取Debian镜像的内核源码并编译
编译4.19.71版本内核

内核模块的功能需要依赖内核提供的各种底层接口

1.下载linux内核源码

​ github:

复制代码
git clone https://github.com/Embedfire/ebf-buster-linux.git

​ gitee:

复制代码
git clone https://gitee.com/Embedfire/ebf-buster-linux.git

2.安装必要环境工具库

复制代码
sudo apt install make gcc-arm-linux-gnueabihf gcc bison flex libssl-dev dpkg-dev lzop

3.一键编译内核

复制代码
sudo ./make_deb.sh

4.获取编译出来的内核相关文件

复制代码
/home/pi/build
内核模块头文件
复制代码
- #include <linux/module.h>:包含内核模块信息声明的相关函数
- #include <linux/init.h>:包含了 module_init()和 module_exit()函数的声明
-  #include <linux/kernel.h>:包含内核提供的各种函数,如printk
内核模块打印函数
  • printf:glibc实现的打印函数,工作于用户空间

  • printk:内核模块无法使用glibc库函数,内核自身实现的一个类printf函数,但是需要指定打印等级。

    复制代码
    - #define KERN_EMERG 	"<0>" 通常是系统崩溃前的信息
    - #define KERN_ALERT          "<1>" 需要立即处理的消息
    - #define KERN_CRIT             "<2>" 严重情况
    - #define KERN_ERR              "<3>" 错误情况
    - #define KERN_WARNING   "<4>" 有问题的情况
    - #define KERN_NOTICE       "<5>" 注意信息
    - #define KERN_INFO            "<6>" 普通消息
    - #define KERN_DEBUG        "<7>" 调试信息

查看当前系统printk打印等级:cat /proc/sys/kernel/printk

  • 当前控制台日志级别
  • 默认消息日志级别
  • 最小的控制台级别
  • 默认控制台日志级别

打印内核所有打印信息:dmesg

  • 内核log缓冲区大小有限制,缓冲区数据可能被冲掉
Makefile分析
  • KERNEL_DIR:指向linux内核具体路径

  • export:导出变量给子Makefile使用

  • obj-m := <模块名>.o:定义要生成的模块

  • $(MAKE):Makefile的默认变量,值为make

  • 选项"-C":让make工具跳转到linux内核目录下读取顶层Makefile

  • M=:表示内核模块源码目录

  • $(CURDIR):Makefile默认变量,值为当前目录所在路径

  • make modules:执行Linux顶层Makefile的伪目标,它实现内核模块的源码读取并编译为.ko文件

编译内核模块
复制代码
make
把生成的内核模块拷贝到nfs共享目录
复制代码
make copy
开发板加载内核模块
复制代码
insmod xxx.ko

内核模块实验2

mobaxterm设置窗口行数、列数

Linux终端窗口

  • 查询终端窗口的行列数:stty size
  • 设置终端窗口列数:stty cols xx
  • 设置终端窗口行数:stty rows xx

mobaxterm窗口

  • 右击会话窗口,选择"edit session "->"Terminal settings"->"Terminial font settings"->"Terminal size"
模块参数

根据不同应用场合给内核模块传递不同参数,提高内核模块灵活性

  • 定义一个常见变量

  • 使用module_param宏把传参值赋给变量

    module_param(name, type, perm)

  • name:参数名

  • type:参数类型,如int、byte、bool、charp...

  • perm:读写权限

    • 不允许设置可执行权限
    • 在"/sys/module/模块名/parameters"目录下,会生成该参数对应的文件名
符号共享

内核模块可以共享导出的符号表

  • 变量共享

  • 函数共享

    EXPORT_SYMBOL(sym)

  • sym:变量名或者函数名

查看符号表
复制代码
cat /proc/kallsyms | grep xxx
Makefile修改
  • 有依赖关系的模块,放在一起进行编译
  • clean伪目标增加清除共享文件夹指令
模块手动加载
  • 加载时,必须先加载相关依赖模块
  • 卸载时,顺序相反
模块自动加载
  • 所有内核模块统一放到"/lib/modules/内核版本"目录下

    复制代码
    cp *.ko /lib/modules/内核版本
  • 建立模块依赖关系:

    复制代码
    depmod -a 
  • 查看模块依赖关系

    复制代码
    cat /lib/modules/内核版本/modules.dep
  • 加载模块及其依赖模块

    复制代码
    modprobe xxx
  • 卸载模块及其依赖模块

    复制代码
    modprobe -r xxx
相关推荐
野生柚子14 分钟前
记录学习K8s 集群中OOM Killer的决策基准及执行流程
linux·运维
TLucas1 小时前
在CentOS 7上将PostgreSQL数据库从默认路径迁移到自定义目录
linux·运维·postgresql·centos
guidovans2 小时前
基于tkinter开发电脑工具集(源码在底部)
linux·windows·python·gui·tkinter
菜菜子爱学习3 小时前
Nginx学习笔记(九)—— Nginx Rewrite深度解析
linux·运维·笔记·学习·nginx
Tearstornbyrain4 小时前
在Ubuntu24.04中使用ssh连接本地git仓库到github远程仓库
linux·git·ubuntu·ssh·github
Jia ming4 小时前
【奔跑吧!Linux 内核(第二版)】第6章:简单的字符设备驱动(三)
linux
bai5459365 小时前
STM32 DMA+AD多通道
stm32·单片机·嵌入式硬件
酷飞飞5 小时前
RTC时钟倒计时数码管同步显示实现(STC8)
单片机·嵌入式硬件·51单片机·嵌入式·stc8
星哥说事6 小时前
如何将堡塔云WAF备份、迁移到新的服务器
linux
ycchenG76 小时前
缓存元数据损坏操作步骤(lvmcache修复)
linux·缓存