OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4823|回复: 1

内核模块的version magic 你知多少?

[复制链接]

1045

主题

1056

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4343
金钱
4343
注册时间
2019-5-8
在线时间
1192 小时
发表于 2021-7-9 12:00:55 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2021-11-1 10:42 编辑

以下文章摘自微信公众号——开源电子网《内核模块的version magic 你知多少?》
更多技术文章,请扫下方二维码关注


开源电子网,扫码2222222.png

本节我们来了解内核模块的version magic,也就是kernel(内核)和内核模块的版本问题。本节的内容是笔者的一些整理和理解,如有不对的地方,希望大家指正,我们互相学习,共同进步。

1. 问题发现
    相信很多小伙伴在跟着《【正点原子】I.MX6U嵌入式Linux驱动开发指南》学习Linux,尤其是刚入门Linux的小伙伴在加载驱动.ko文件的时候可能会遇见类似如下报错:
  1. version magic '4.1.15 SMP preempt mod_unload modversions ARMv6 p2v8 ' should be '4.1.15-
复制代码
内核模块的version magic 你知多少1487.png
图1. 1 报错信息

    以上报错信息提示当前插入led.ko的version magic版本信息与正在运行的内核的version magic版本不一致,led.ko的version magic版本信息是” 4.1.15 SMP preempt mod_unload modversions ARMv6 p2v8”,kernel的version magic版本信息是” 4.1.15-gad512fa SMP preempt mod_unload modversions ARMv7 p2v8”。
    出现这种问题的原因一般是kernel与内核模块没有同时更新导致版本不一样,比如新编译的模块所对应的kernel和板子上正在运行的kernel发生了变化,模块与板子上的kernel存在不兼容等,导致模块加载失败。上面的问题正是小伙伴拿到板子以后,直接使用板子烧录好的kernel而并没有使用自己编译的kernel来做驱动实验而导致的错误。


2. 如何查看内核版本和内核模块版本2.1 uname和modinfo指令用法
2.1 uname指令主要用于查询kernel版本相关信息,用法:
uname [选项参数]
  1. 选项参数如下:
  2. -a,依次按照如下选项输出有关信息:
  3. -s, 输出kernel名称;
  4. -n, 输出主机名;
  5. -r, 输出kernel发行版本号;
  6. -v, 输出操作系统版本;
  7. -m, 输出主机的硬件架构名称;
  8. -p, 输出处理器类型;
  9. -i, 输出硬件平台;
  10. -o, 输出操作系统名称
复制代码
      一般用的较多的是uname -r和uname -a。
     modinfo主要用于查看内核模块的信息,用法:
modinfo 模块名

2.2 查看kernel和内核模块版本
    在开发板文件系统下执行uname –r可以查看kernel发行版号,执行如下指令:
  1. uname -r
复制代码
    在文件系统的/lib/modules下,可以查看内核模块版本(/lib/modules/下的文件夹):
内核模块的version magic 你知多少2347.png

图2.2. 1 查看kernel和内核模块版本信息
    可以看到,kernel和内核模块的发行版本号都是4.1.15-gad512fa。
    uname –r查看的是内核发行版本号,uname –a可以查看更具体的版本信息,如下:
  1. uname -a
复制代码
内核模块的version magic 你知多少2496.png

图2.2. 2 查看kernel具体版本信息
  1. 内核名称:Linux
  2. 主机名:ATK-IMX6U
  3. kernel发行版号:4.1.15-gad512fa
  4. 操作系统版本和时间:#1 SMP PREEMPT Mon Mar 29 16:02:02 CST 2021
  5. 硬件架构、处理器类型和硬件平台都是armv7l
  6. 操作系统名称:GNU/Linux
复制代码

    当开发板启动到kernel阶段时,kernel启动时也会打印kernel的版本号:
  1. Linux version 4.1.15-gad512fa (alientek@ubuntu) (gcc version 5.3.0 (GCC) ) #1 SMP PREEMPT Mon Mar 29 16:02:02 CST 2021
复制代码
    以上信息中(alientek@ubuntu)是编译kernel所使用的机器,其中,alientek是用户名,ubuntu是主机名。(gcc version 5.3.0 (GCC) )是gcc版本。通过(alientek@ubuntu)这一串打印信息,可以初步判断板子上的kernel是否是自己的ubuntu编译出来的(因为不同用户设置的ubuntu用户名会不一样),最后一串Mon Mar 29 16:02:02 CST 2021可以显示编译kernel的时间,我们在替换kernel的时候也可以通过这个时间信息来区分此时板子上的kernel是否是我们刚替换的kernel。
内核模块的version magic 你知多少3145.png

图2.2. 3 开发板kernel启动的信息
2.3 查看加载模块.ko版本信息
    查看所加载的模块.ko版本:
  1. modinfo led.ko
复制代码
内核模块的version magic 你知多少3242.png

图2.3. 1 查看led.ko版本信息
  1. root@ATK-IMX6U:/lib/modules/4.1.15-gad512fa# modinfo led.ko
  2. filename:/lib/modules/4.1.15-gad512fa/led.ko
  3. author: zuozhongkai
  4. license: GPL
  5. srcversion: 597E1DDC8A372707B8FD0DE
  6. depends:        
  7. vermagic: 4.1.15 SMP preempt mod_unload modversions ARMv6 p2v8
复制代码
对以上基本信息的简单解释:
  1. filename: 文件路径
  2. author: 显示模块开发人员
  3. license: 协议
  4. srcversion: 版本信息
  5. depends: 依赖文件
  6. vermagic:即 Version Magic String,也就是编译模块时的内核版本以及SMP与PREEMPT等配置信息。
复制代码
    根据打印信息可以知道,在led.ko文件的版本信息中,发行版号是4.1.15,和前面kernel发行版本号4.1.15-gad512fa不一致,而且显示ARMv6,而不是ARMv7,这就会导致模块.ko文件无法加载,所以会报前文的错误。


3. kernel版本由什么控制

    下面,笔者以自己移植的kernel为例进行讲解。
3.1 kernel基础版本号
    在内核源码根目录的Makefile下可以看到Linux kernel的基础版本号,如下,Linux kernel基础版本号为 4.1.15:
内核模块的version magic 你知多少3949.png

图3.1. 1 kernel源码根目录下Makefile文件

3.2 kernel拓展版本号
    kernel引入了一些配置信息来增强版本信息,在内核源码的include/linux/vermagic.h下我们可以看到模块的健全版本信息,如下默认配置的有:
  1. MODULE_VERMAGIC_SMP=SMP;
  2. MODULE_VERMAGIC_PREEMPT= preempt;
  3. MODULE_VERMAGIC_MODULE_UNLOAD=mod_unload;
  4. MODULE_VERMAGIC_MODVERSIONS= modversions;
复制代码
    其余选项的宏是空的,还有一个VERMAGIC_STRING宏:
  1. #define VERMAGIC_STRING         \
  2. UTS_RELEASE " "      \
  3. MODULE_VERMAGIC_SMP  MODULE_VERMAGIC_PREEMPT                   \
  4. MODULE_VERMAGIC_MODULE_UNLOAD  MODULE_VERMAGIC_MODVERSIONS  \
  5. MODULE_ARCH_VERMAGIC
复制代码
内核模块的version magic 你知多少4499.png

图3.2. 1 vermagic.h文件内容
    其中,UTS_RELEASE的配置在内核源码的include/generated/utsrelease.h下可以看到, utsrelease.h的内容是由Makefile和.config的内容进行生成的,当成功编译kernel以后,utsrelease.h得到更新,如下:
  1. #define UTS_RELEASE "4.1.15"
复制代码
内核模块的version magic 你知多少4715.png

图3.2. 2 utsrelease.h文件内容
    那么前文4.1.15-gad512fa中的-gad512fa是如何得来的呢?其实这个是开发者使用了Git来管理代码(也有使用SVN来管理代码)。如果你在开发的时候ubuntu安装了Git,在代码维护上可以使用Git来维护,当你修改或者提交代码以后,那么在UTS_RELEASE后面就会看到一串数字,例如4.1.15-gad512fa,-gad512fa这个就是Git版本控制而产生的。
    4.1.15-gad512fa这一串就组成了kernel发行版本号,发行版本号只是各个厂商用于区别自己发布的不同时期的kernel版本或者产品版本而产生的编号,完全由各厂商自己定义。
    这么一来,我移植的内核模块的部分版本信息就确定了,也就是:
  1. 4.1.15  SMP  preempt   mod_unload  modversions
复制代码
    led.ko模块在编译时,kernel的版本信息会被添加到模块的modinfo段中,所以我们可以通过modinfo led.ko来查看模块的version magic信息,在加载模块的时候,装载器会比较kernel的version magic与模块modinfo段里的version magic信息,如果它们信息一致,模块才可以被加载,否则就会报错前文的信息,或者报错找不到模块,如:“could not search modules: No such file or directory”,又或者报错“Invalid module format”。

3.3 CPU核心家族选择
    此外,还注意到前面提示的ARMv7和ARMv6不一样,他们是CPU核心家族,ARM11是ARMv6架构,Cortex-A、Cortex-R、Cortex-M三个系列是ARMv7架构,我们使用的阿尔法开发板的CPU是Cortex-A7内核,所以是基于 ARMv7 的平台,ARMv7是向下兼容ARMv6的。CPU核心家族选项可以在配置内核的时候进行选择。

4. 问题解决

    针对前文出现的问题,下面我给出两种解决办法。

4.1 同步更新kernel、内核模块(推荐)
    使用同一个内核源码重新编译kernel、设备树和内核模块,然后将板子的kernel和设备树一起更新,并安装内核模块,这一步做好以后再去做驱动实验部分。
  1. <font color="#2e8b57">/* 编译内核 */</font>
  2. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage
  3. <font color="#2e8b57">/* 编译设备树(设备树名字根据自己的实际情况来写) */</font>
  4. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ull-alientek-emmc.dtb
  5. <font color="#2e8b57">/* 编译内核模块 */</font>
  6. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules
  7. <font color="#2e8b57">/* 安装内核模块 */</font>
  8. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_install INSTALL_MOD_PATH=<font color="#9932cc">后面加上文件系统的路径</font>
复制代码

内核模块的version magic 你知多少6205.png

图4.2. 1 修改内核源码根目录Makefile下的EXTRAVERSION
执行如下指令重新配置内核:
  1. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
复制代码
配置如下,在System Typeà Multiple platform selectioà ARMv6 based platforms (ARM11)下将CPU核心家族选择的ARMv6 based platforms (ARM11)选项去掉,只留下ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)这项:
内核模块的version magic 你知多少6529.png

图4.2. 2 选择CPU核心家族
    然后重新编译kernel,在这个过程中,修改Makefile下的EXTRAVERSION =-gad512fa以后,重新编译kernel,最终kernel发行版本4.1.15-gad512fa信息会根据Makefile和.config的内容进行生成并记录在内核源码的include/generated/utsrelease.h下,如下是我编译kernel以后utsrelease.h文件的内容:
  1. #define UTS_RELEASE "4.1.15-gad512fa"
复制代码
内核模块的version magic 你知多少6810.png

图4.2. 3 编译后查看utsrelease.h文件的内容
接着我们再编译led.ko文件,再次使用modinfo led.ko查看模块信息:
内核模块的version magic 你知多少6909.png

图4.2. 4 查看重新编译的led.ko的版本信息
查看led.ko版本信息是4.1.15-gad512fa SMP preempt mod_unload modversions ARMv7 p2v8,将led.ko重新拷贝到板子上(板子上的kernel不必更新),再次加载led.ko不再报错:
内核模块的version magic 你知多少7086.png

图4.2. 5 加载led.ko不再报错




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

8

主题

888

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
2377
金钱
2377
注册时间
2019-9-25
在线时间
394 小时
发表于 2021-7-9 21:33:50 | 显示全部楼层
详细文章,在 正点原子  开源电子网 公众号上可以看,链接:
https://mp.weixin.qq.com/s/IFDd5am26K1rImLXjoBhEw
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-5-8 23:41

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表