如何修改内核版本号,使驱动与内核版本匹配

本文介绍了如何在内核与驱动版本不匹配时,通过修改KERNELRELEASE变量和使用setlocalversion脚本来调整内核版本号以适应驱动。还提及了驱动加载时的vermagic检查和modprobe命令中的忽略选项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在加载驱动时,内核版本与驱动版本是必须严格匹配的,否则会出现驱动加载失败的情况。当驱动与内核版本不匹配时,最快的方法自然是更换内核或驱动。但面对一些特殊情况时,不得不修改内核版本号强行匹配驱动版本,本文将就该问题进行处理。

内核版本号是如何生成的

在kernel根目录的Makefile中可以查到,内核版本号(KERNELRELEASE)储存在include/config/kernel.release中,会在编译内核时生成。可以通过cat命令查看内核版本号。

cat include/config/kernel.release
4.4.77-gb1fd820b-dirty

那么kernel.release这个文件是如何生成的呢?

在Makefile中,使用路径include/config/kernel.release作为搜索关键词可以找到kernel.release的生成过程。

# Store (new) KERNELRELEASE string in include/config/kernel.release
include/config/kernel.release: include/config/auto.conf FORCE
    $(call filechk,kernel.release)
define filechk_kernel.release
#这段代码的目的是在生成 kernel.release 文件时,使用内核版本号和执行 setlocalversion 脚本的结果作为文件的内容。
    echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"
endef

可知,(KERNELRELEASE)由两部分组成,分别是变量$(KERNELVERSION)与setlocalversion 脚本的执行结果。

  1. 变量$(KERNELVERSION)

在Makefile中搜索KERNELVERSION变量,可以发现该变量是在Makefile最开头定义的,因此修改如下变量就可以修改KERNELVERSION

VERSION = 4
PATCHLEVEL = 4
SUBLEVEL = 77
EXTRAVERSION =
NAME = Blurry Fish Butt

#......

KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
  1. setlocalversion 脚本

# localversion* files in the build and source directory
res="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
        res="$res$(collect_files "$srctree"/localversion*)"
fi

# CONFIG_LOCALVERSION and LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"

# scm version string if not at a tagged commit
if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
        # full scm version string
        res="$res$(scm_version)"
else
        # append a plus sign if the repository is not in a clean
        # annotated or signed tagged state (as git describe only
        # looks at signed or annotated tags - git tag -a/-s) and
        # LOCALVERSION= is not specified
        if test "${LOCALVERSION+set}" != "set"; then
                scm=$(scm_version --short)
                res="$res${scm:++}"
        fi
fi

与变量CONFIG_LOCALVERSION_AUTO,是否定义LOCALVERSION有关

CONFIG_LOCALVERSION_AUTO:也许在deconfig里面?

LOCALVERSION:盲猜是自定义的本地个性化版本号,这里先不管

setlocalversion的版本号生成分几种情况:

  1. 如果 CONFIG_LOCALVERSION_AUTO=y, 则会在最终的LOCALVERSION后追加一段由版本控制工具git或者svn生成的版本信息, 对于git, 如果打了tag,则会使用tag, 否则, 使用字母‘g’再加上最新的commit ID的前7位, 例如 “4.4.77-gb1fd820b-dirty”, 若存在未被追踪的修改, 则还会添加” -dirty”字样
  2. 如果 CONFIG_LOCALVERSION_AUTO=n, 且未指定LOCALVERSION变量则会在最终的LOCALVERSION后追加‘+’, 例如 “3.10.49+”
# Check for git and a git repo.
        if test -z "$(git rev-parse --show-cdup 2>/dev/null)" &&
           head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
           
#tips:git rev-parse --verify --short HEAD:获取最新commit id的简短结果

                # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
                # it, because this version is defined in the top level Makefile.
                if [ -z "`git describe --exact-match 2>/dev/null`" ]; then

                        # If only the short version is requested, don't bother
                        # running further git commands
                        if $short; then
                                echo "+"
                                return
                        fi
                        # If we are past a tagged commit (like
                        # "v2.6.30-rc5-302-g72357d5"), we pretty print it.
                        if atag="`git describe 2>/dev/null`"; then
                                echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'

                        # If we don't have a tag at all we print -g{commitish}.
                        else
                                printf '%s%s' -g $head
                        fi
                fi

                # Is this git on svn?
                if git config --get svn-remote.svn.url >/dev/null; then
                        printf -- '-svn%s' "`git svn find-rev $head`"
                fi

                # Check for uncommitted changes
                if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then
                        printf '%s' -dirty
                fi

                # All done with git
                return
        fi

源码:

#!/bin/sh
#
# This scripts adds local version information from the version
# control systems git, mercurial (hg) and subversion (svn).
#
# If something goes wrong, send a mail the kernel build mailinglist
# (see MAINTAINERS) and CC Nico Schottelius
# <nico-linuxsetlocalversion -at- schottelius.org>.
#
#

usage() {
        echo "Usage: $0 [--save-scmversion] [srctree]" >&2
        exit 1
}

scm_only=false
srctree=.
if test "$1" = "--save-scmversion"; then
        scm_only=true
        shift
fi
if test $# -gt 0; then
        srctree=$1
        shift
fi
if test $# -gt 0 -o ! -d "$srctree"; then
        usage
fi

scm_version()
{
        local short
        short=false

        cd "$srctree"
        if test -e .scmversion; then
                cat .scmversion
                return
        fi
        if test "$1" = "--short"; then
                short=true
        fi

        # Check for git and a git repo.
        if test -z "$(git rev-parse --show-cdup 2>/dev/null)" &&
           head=`git rev-parse --verify --short HEAD 2>/dev/null`; then

                # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
                # it, because this version is defined in the top level Makefile.
                if [ -z "`git describe --exact-match 2>/dev/null`" ]; then

                        # If only the short version is requested, don't bother
                        # running further git commands
                        if $short; then
                                echo "+"
                                return
                        fi
                        # If we are past a tagged commit (like
                        # "v2.6.30-rc5-302-g72357d5"), we pretty print it.
                        if atag="`git describe 2>/dev/null`"; then
                                echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'

                        # If we don't have a tag at all we print -g{commitish}.
                        else
                                printf '%s%s' -g $head
                        fi
                fi

                # Is this git on svn?
                if git config --get svn-remote.svn.url >/dev/null; then
                        printf -- '-svn%s' "`git svn find-rev $head`"
                fi

                # Check for uncommitted changes
                if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then
                        printf '%s' -dirty
                fi

                # All done with git
                return
        fi

        # Check for mercurial and a mercurial repo.
        if test -d .hg && hgid=`hg id 2>/dev/null`; then
                # Do we have an tagged version?  If so, latesttagdistance == 1
                if [ "`hg log -r . --template '{latesttagdistance}'`" == "1" ]; then
                        id=`hg log -r . --template '{latesttag}'`
                        printf '%s%s' -hg "$id"
                else
                        tag=`printf '%s' "$hgid" | cut -d' ' -f2`
                        if [ -z "$tag" -o "$tag" = tip ]; then
                                id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
                                printf '%s%s' -hg "$id"
                        fi
                fi

                # Are there uncommitted changes?
                # These are represented by + after the changeset id.
                case "$hgid" in
                        *+|*+\ *) printf '%s' -dirty ;;
                esac

                # All done with mercurial
                return
        fi

        # Check for svn and a svn repo.
        if rev=`LANG= LC_ALL= LC_MESSAGES=C svn info 2>/dev/null | grep '^Last Changed Rev'`; then
                rev=`echo $rev | awk '{print $NF}'`
                printf -- '-svn%s' "$rev"

                # All done with svn
                return
        fi
}

collect_files()
{
        local file res

        for file; do
                case "$file" in
                *\~*)
                        continue
                        ;;
                esac
                if test -e "$file"; then
                        res="$res$(cat "$file")"
                fi
        done
        echo "$res"
}

if $scm_only; then
        if test ! -e .scmversion; then
                res=$(scm_version)
                echo "$res" >.scmversion
        fi
        exit
fi

if test -e include/config/auto.conf; then
        . include/config/auto.conf
else
        echo "Error: kernelrelease not valid - run 'make prepare' to update it"
        exit 1
fi

# localversion* files in the build and source directory
res="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
        res="$res$(collect_files "$srctree"/localversion*)"
fi

# CONFIG_LOCALVERSION and LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"

# scm version string if not at a tagged commit
if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
        # full scm version string
        res="$res$(scm_version)"
else
        # append a plus sign if the repository is not in a clean
        # annotated or signed tagged state (as git describe only
        # looks at signed or annotated tags - git tag -a/-s) and
        # LOCALVERSION= is not specified
        if test "${LOCALVERSION+set}" != "set"; then
                scm=$(scm_version --short)
                res="$res${scm:++}"
        fi
fi

echo "$res"
  1. 修改内核版本号:

    于是我们得出修改内核版本号的方法:

    • 修改kernel目录下的版本号定义
    • 修改CONFIG_LOCALVERSION_AUTO
    • 修改LOCALVERSION

驱动与内核版本检查

当通过insmod或modprobe加载核外驱动ko时,会进行模块版本检测。当kernel的版本与驱动的vermagic不同时,系统会报错,提示无法加载模块。

  1. 查看驱动的版本

modinfo [.ko]/
  1. 忽略版本检查

使用modprobe命令加载模块时, 提供了两个选项, 用于在加载模块时忽略vermagic或者CRC检查, 强制加载一个模块

不建议 怕崩溃

–force-vermagic : 忽略vermagic检查

–force-modversion : 忽略CRC检查

-f : 相当于同时使用 –force-vermagic 和 –force-modversion

参考资料

linux内核模块版本检查

内核版本模块检查

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值