首页 / 资讯中心 / 文章详情

银河麒麟V10下e1000e/RTL8125驱动编译与加载排错

银河麒麟V10下e1000e/RTL8125驱动编译与加载排错 ★ FEATURED ARTICLE
简介面向银河麒麟V10国产化环境开展网卡驱动适配的运维与开发人员这份源码包提供已在系统中编译通过的e1000e与RTL8125驱动可用于解决Intel千兆网卡及Realtek RTL8125B/C网卡在该平台上的识别、加载与联网问题。包体共56个文件以C源码、头文件为主辅以Makefile构建脚本、README说明、spec打包描述及补丁与兼容层文件压缩后约483KB目录按两套驱动源码分包组织便于对照内核接口与编译配置。已有2750人学习下载。其价值在于给出可复现的编译基础e1000e部分涉及源码重复定义清理RTL8125部分涉及函数参数调整配合构建脚本和说明文档读者可据此完成源码审查、编译加载与基本连通性验证也能为同类信创平台的驱动移植和排错提供参考。1. 银河麒麟 V10 编译 e1000e/RTL8125 驱动别先改源码先看内核头文件银河麒麟 V10 下编译 e1000e 和 RTL8125 网卡驱动最容易翻车的不是驱动源码本身而是内核头文件、内核版本和签名这三道关。很多人拿到源码直接make看到make: *** /lib/modules/.../build: No such file or directory就以为源码缺文件也有人编译通过insmod却报Invalid module format。这类故障适合正在给老机器补 2.5G 网卡、或者把 e1000e 驱动替换成新版本的人。先别急着改 C 代码按内核头文件、源码 API、模块加载三层往下排后面会少踩很多坑。RTL8125 这类 2.5G 网卡和 e1000e 这类千兆网卡驱动在银河麒麟 V10 的不同 SP 版本上内核差异不小报错长得像根因经常不在一层。2./lib/modules/$(uname -r)/build不存在内核头文件缺失与版本错位2.1 报错现场make 停在不存在的 build 目录最常见的现场是进了驱动源码目录直接敲make第一行就停make: *** /lib/modules/$(uname -r)/build: No such file or directory. Stop.这时候不要急着怀疑源码缺文件。先把$(uname -r)展开成实际内核版本再看/lib/modules/下面到底有什么。我一般会先跑三条命令uname -r看当前运行内核ls -l /lib/modules/$(uname -r)/build看软链指向ls /usr/src/看头文件目录在不在。三條命令一对照问题基本就分成两类一类是头文件包根本没装另一类是装了但装的是别的内核版本build软链断掉。# 当前运行内核 uname -r # build 软链是否存在、指向哪里 ls -l /lib/modules/$(uname -r)/build # 头文件目录是否真的存在 ls -d /usr/src/linux-headers-$(uname -r) 2/dev/null上面这段没有编译动作只是把“运行内核”和“头文件目录”对齐。uname -r输出的是当前启动的内核版本/lib/modules/$(uname -r)/build正常应该是一个软链指向/usr/src/linux-headers-$(uname -r)一类的目录。如果ls -l显示No such file or directory说明这个软链不存在如果软链存在但ls -d找不到目标说明软链是断的。两种情况的处理不一样后面分开说。2.2 根因头文件包没装还是内核版本对不上外部模块编译不是只靠 gcc 和 make它需要当前内核的配置、头文件和Module.symvers。内核头文件包的名字通常带内核版本比如桌面版常见linux-headers-$(uname -r)服务器版常见kernel-devel-$(uname -r)。很多人只装了linux-headers-generic或者kernel-devel不带版本结果装上去的是仓库里最新内核的头文件而机器实际启动的还是老内核。build软链指向新内核目录编译出来的模块 vermagic 也是新内核加载时当然对不上。还有一种情况是系统刚升级过内核/lib/modules/下有两个版本目录但/usr/src/只保留了新版本头文件老内核的build软链就断了。这个时候make报的是 build 不存在根因却是“头文件和运行内核错位”。所以不要只看报错行先确认uname -r和/usr/src/下的目录名是不是同一个版本。2.3 解决装对 headers再验证 build 指向确认是头文件缺失后按系统的包管理器装对应版本。银河麒麟 V10 桌面版常见 Debian 系包管理服务器版常见 RHEL 系包管理先看/etc/os-release再选命令不要混用。# Debian/Ubuntu 系常见安装方式 sudo apt update sudo apt install -y linux-headers-$(uname -r) build-essential # RHEL/CentOS 系常见安装方式 sudo yum install -y kernel-devel-$(uname -r) kernel-headers-$(uname -r) gcc make # 装完立即验证 ls -l /lib/modules/$(uname -r)/build test -f /lib/modules/$(uname -r)/build/Makefile echo build ok test -f /lib/modules/$(uname -r)/build/Module.symvers echo symvers ok这段命令的逻辑是先把包名锁到当前内核版本再检查三个东西build软链、Makefile、Module.symvers。包名里的$(uname -r)不能省省了就可能装成最新内核的头文件。build-essential提供 gcc、make 等基础工具kernel-headers提供用户态头文件kernel-devel提供内核构建目录。Module.symvers很关键它记录内核符号版本缺失时 modpost 会警告严重时模块加载报版本不一致。test -f只做存在性检查返回build ok和symvers ok才算基础环境齐了。如果Module.symvers缺失优先换完整的kernel-devel包不要从别的内核目录复制一个过来凑数复制出来的符号版本大概率对不上。2.4 参数说明-C和M到底在做什么头文件装好之后编译外部模块不要直接make用内核构建目录来驱动# 在驱动源码目录执行 make -C /lib/modules/$(uname -r)/build M$PWD modules-C是让 make 先切换到内核构建目录读内核顶层的 MakefileM$PWD告诉内核构建系统“外部模块源码在当前目录”modules是构建目标。这样编译出来的模块才会带上当前内核的配置和符号版本。直接make只读驱动自己的 Makefile如果驱动顶层 Makefile 没写对KDIR就会落到默认路径或者空路径报错看起来像源码问题实际是构建入口不对。如果驱动自带 Makefile检查里面的KDIR是不是用了$(shell uname -r)。有些源码包为了兼容把KDIR写死成/lib/modules/$(shell uname -r)/build这种一般没问题写死成某个固定路径的换机器就翻车。失败时先看第一条error不要看最后一行make: ***最后一行通常只是“上层目标失败”的汇总。2.5 什么时候需要软链什么时候不要碰只有确认/usr/src/linux-headers-$(uname -r)存在而/lib/modules/$(uname -r)/build缺失或断链时才考虑手动补软链# 先确认目标目录存在 ls -d /usr/src/linux-headers-$(uname -r) # 再建软链-f 覆盖旧链接-n 避免把软链当目录 sudo ln -sfn /usr/src/linux-headers-$(uname -r) /lib/modules/$(uname -r)/build # 验证链接最终指向 readlink -f /lib/modules/$(uname -r)/buildln -sfn里-s建软链-f覆盖已有文件-n防止目标本身是软链时被当成目录处理。readlink -f会展开到最终路径返回空就说明还是断链。这个操作不是常规步骤发行版头文件包一般会自动建好软链手动补链只适合自己编译内核源码到/usr/src/linux的场景。链错比没链更难查因为make可能不报 build 不存在而是报一堆头文件里的类型缺失看着像驱动源码不兼容。注意不要从另一个内核版本复制build目录或Module.symvers来“先编过再说”编出来的模块加载时会报module_layout版本不一致问题只是从编译期推迟到加载期。3. RTL8125 编译报implicit declaration旧驱动撞上新内核 API3.1 报错现场RTL8125 源码在pci_alloc_consistent处停住RTL8125 的驱动源码如果来自较早的版本在银河麒麟 V10 较新内核上编译常见报错不是找不到文件而是函数声明对不上r8125_n.c: In function ‘rtl8125_init_one’: r8125_n.c: error: implicit declaration of function ‘pci_alloc_consistent’; did you mean ‘dma_alloc_coherent’? r8125_n.c: error: too few arguments to function ‘netif_napi_add’ r8125_n.c: error: ‘init_timer’ undeclared这类报错有一个共同点源码里调的接口在当前内核头文件里已经改了签名或者被移除。implicit declaration不是“少 include 一个头文件”这么简单很多时候是接口本身没了。继续往下编还会出现assignment from incompatible pointer type、unknown type name之类的连锁错误。看到第一屏报错就停先把第一处 API 对不上的位置找出来。3.2 根因源码里的内核 API 比当前内核老RTL8125 驱动是外部模块它依赖内核内部 API。内核升级时这些 API 不会保持永久兼容。常见变化有几类pci_alloc_consistent这类 PCI DMA 接口逐步被dma_alloc_coherent取代netif_napi_add的 weight 参数在新内核里被拆到netif_napi_add_weightinit_timer被timer_setup取代ndo_tx_timeout的返回值、skb_shinfo的访问方式也改过。驱动源码如果按老内核写编译时就会在这些点上报错。这里要区分“驱动源码太老”和“内核头文件不完整”。如果报错集中在linux/module.h、linux/netdevice.h找不到先回头查第 2 章的 headers如果报错集中在驱动自己的.c文件里函数名和参数对不上基本就是 API 兼容问题。前者是环境没搭好后者是源码要适配处理顺序不能反。3.3 解决先换驱动版本再打兼容补丁第一选择不是一行行改驱动而是找一份已经适配当前内核的 RTL8125 源码。外部驱动动辄几千行API 变化可能涉及十几处手工补容易漏。资源里整理的可编译版本就是按这个思路来的先把源码版本和内核 API 对齐再保留必要的兼容宏。只有找不到合适版本时才在驱动自己的头文件里做薄封装。#include linux/version.h #include linux/dma-mapping.h #include linux/netdevice.h /* 老接口 pci_alloc_consistent 在新内核用 dma_alloc_coherent 替代 */ #if LINUX_VERSION_CODE KERNEL_VERSION(5, 0, 0) #define rtl8125_pci_alloc_consistent(pdev, size, dma) \ pci_alloc_consistent(pdev, size, dma) #else #define rtl8125_pci_alloc_consistent(pdev, size, dma) \ dma_alloc_coherent((pdev)-dev, size, dma, GFP_KERNEL) #endif /* netif_napi_add 的 weight 参数在新内核被拆到 netif_napi_add_weight */ #if LINUX_VERSION_CODE KERNEL_VERSION(6, 1, 0) #define rtl8125_napi_add(dev, napi, poll, weight) \ netif_napi_add_weight(dev, napi, poll, weight) #else #define rtl8125_napi_add(dev, napi, poll, weight) \ netif_napi_add(dev, napi, poll, weight) #endif这段兼容层的关键是“只包一层不改调用语义”。LINUX_VERSION_CODE来自linux/version.h用KERNEL_VERSION做版本比较dma_alloc_coherent的第一个参数是设备结构所以从pci_dev取pdev-devGFP_KERNEL表示可睡眠上下文分配。netif_napi_add_weight在较新内核里承接原来的 weight 参数老内核仍然走四参数版本。调用点改成rtl8125_pci_alloc_consistent和rtl8125_napi_add不要全局替换所有netif_napi_add否则可能把别的模块接口也改掉。兼容宏放在驱动自己的头文件里不要改内核源码树。3.4 编译参数和验证外部模块构建RTL8125 源码顶层 Makefile 要确认KDIR和obj-m没写错obj-m r8125.o r8125-objs : r8125_n.o r8125_rss.o KVER : $(shell uname -r) KDIR : /lib/modules/$(KVER)/build all: $(MAKE) -C $(KDIR) M$(PWD) modules clean: $(MAKE) -C $(KDIR) M$(PWD) cleanobj-m声明要构建成模块的目标r8125-objs把多个源文件链接成一个r8125.ko。KVER用uname -r取当前内核KDIR指向当前内核构建目录$(MAKE)调用 make 自身避免递归时丢失环境M$(PWD)指定外部模块目录。这个 Makefile 不负责安装只负责编译和清理安装动作后面单独做。# 清掉旧对象避免跨内核 .o 混入 make clean # 用当前内核构建目录编译 make -C /lib/modules/$(uname -r)/build M$PWD modules # 看模块版本信息和 vermagic modinfo ./r8125.ko | grep -E filename|version|vermagicmake clean不是可选项尤其是从别的机器拷来的源码目录旧.o可能按另一个内核编译过混进来会让报错位置很怪。modinfo里重点看vermagic它应该包含当前uname -r的版本信息。如果vermagic不对不要继续加载回到第 4 章处理内核版本错位。如果编译通过但modpost报missing MODULE_LICENSE在驱动源文件里补MODULE_LICENSE(GPL)许可证声明缺失会影响模块加载和符号导出。3.5 失败时看dmesg和modpost警告编译阶段的错误看终端第一处error加载阶段的错误看dmesg | tail -50。RTL8125 加载失败常见两类一类是Unknown symbol说明模块依赖的符号没导出通常是内核配置或符号版本问题另一类是r8125: probe of ... failed with error -2说明驱动入口跑了但设备初始化失败可能是设备 ID 没匹配、固件缺失或者被别的驱动先占用。modpost的警告不要全忽略WARNING: modpost: missing MODULE_LICENSE()这种要补WARNING: Symbol version dump ... not found要回头查Module.symvers。加载前先确认没有旧模块占着设备。RTL8125 的 2.5G 网卡可能被内核自带的r8169驱动先接管lsmod | grep r8169能看到。如果r8169已经加载直接insmod r8125.ko可能不报错但网卡不出现因为设备已经被前一个驱动 probe 了。处理方式在第 5 章避坑里展开。4. e1000e 加载报module_layout或Required key not available编译内核和运行内核不是同一个4.1 报错现场disagrees about version of symbol module_layoute1000e 编译通过insmod时出现insmod: ERROR: could not insert module e1000e.ko: Invalid module format dmesg: e1000e: version magic ... should be ... e1000e: disagrees about version of symbol module_layoutInvalid module format是用户态工具给的概括真正原因在dmesg里。version magic那一行会打印模块编译时的 vermagic 和当前内核期望的 vermagic两个字符串不一致就加载失败。module_layout是内核导出的符号disagrees about version of symbol module_layout说明模块的符号版本和当前内核的符号版本对不上。很多人看到这里去改源码其实源码没问题是编译环境用错了内核。4.2 根因编译时内核源码和运行内核不是同一个外部模块的 vermagic 来自编译时使用的内核构建目录。make -C /lib/modules/$(uname -r)/build里的uname -r如果和当前运行内核不一致或者build软链指向了另一个内核编出来的模块就带另一个内核的版本信息。还有一种情况是编译目录里残留了旧内核的.o和.cmd文件make没有全部重编链接时混入了旧对象。CONFIG_MODVERSIONS打开时内核还会校验符号 CRCModule.symvers不是当前内核的也会报module_layout或disagrees about version of symbol。先对齐三样东西uname -r的输出、/lib/modules/$(uname -r)/build的最终指向、modinfo ./e1000e.ko里的 vermagic。三者不一致就不要往下加载。不要用--force强行加载强制加载可能让内核在后续收包时崩掉排查成本更高。4.3 解决锁定当前内核重编清理旧对象确认是版本错位后按当前内核重新清理、重新编译# 当前运行内核 uname -r # 清掉旧编译产物 make clean # 严格用当前内核的 build 目录重编 make -C /lib/modules/$(uname -r)/build M$PWD modules # 对比模块 vermagic 和当前内核 modinfo ./e1000e.ko | grep -E vermagic|filename uname -rmake clean要放在最前面尤其是驱动目录从别的机器拷贝过来时。make -C的路径必须用$(uname -r)展开后的当前内核不能写死。modinfo的vermagic和uname -r对比时注意 vermagic 里除了版本号还可能带SMP、preempt等配置标记这些标记也要和当前内核一致。如果vermagic一致但加载仍报符号版本错误检查/lib/modules/$(uname -r)/build/Module.symvers是不是当前内核的缺失就重装对应的kernel-devel包。4.4 Secure Boot 签名报错Required key not available还有一种加载失败不是版本问题而是签名问题modprobe: ERROR: could not insert e1000e: Required key not available系统开启 Secure Boot 时内核只加载有有效本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站