本文主要基于麒麟常见系统版本不同场景用户需求下编译驱动步骤整理得来,仅供参考。
- 编译内核驱动
此处以编译usbmon驱动为例,利用开源内核源码编译。
1、确认目标系统环境及内核信息
编译环境系统版本:Kylin-4.0.2-desktop-sp4-20200728.J1-x86_64,此版本系统内核为4.4.131,因此可以从网上下载4.4.131版本内核源码编译。
2、获取内核源码
内核源码下载地址:linux-kernel安装包下载_开源镜像站-阿里云
内核源码版本:4.4.131.tar.gz
- 解压内核源码执行编译
# tar -xvf linux-4.4.131.tar.gz
# cd linux-4.4.131/drivers/usb/mon
# vim Makefile
#
# Makefile for USB monitor
#
usbmon-y := mon_main.o mon_stat.o mon_text.o mon_bin.o
obj-$(CONFIG_USB_MON) += usbmon.o
查看Makefile文件中是否有多余的选项,此处只有一个驱动,因此不需要删除多余的选项,直接执行编译动作。
# make -C /lib/modules/4.4.131-20200710.kylin.x86-generic/build M=`pwd`
编译完成后可以看到当前目录多了很多以.o和.ko结尾的文件,这个usbmon.ko就是我们需要的文件,测试一下插入该驱动模块
#insmod usbmon.ko
#lsmod | grep usbmon
如果显示出结果则说明没问题。
注意:编译完成如果insmod后lsmod未查询到结果,则可通过dmesg查看之前执行操作的结果,可能会遇到提示校验失败的,dmesg日志如下
module verification failed: signature and/or required key missing - tainting kernel。
此时可通过修改Makefile文件重新编译解决问题。修改后Makefile文件内容如下:
#
# Makefile for USB monitor
#
#CONFIG_MODULE_SIG = n
usbmon-y := mon_main.o mon_stat.o mon_text.o mon_bin.o
obj-$(CONFIG_USB_MON) += usbmon.o
- 编译网卡驱动
此处以编译e1000e驱动为例,驱动源码从官网下载,编译环境系统版本:Kylin-4.0.2-desktop-sp4-20200728.J1-x86_64。
- 解压驱动源码
# tar -zxf e1000e-3.6.0.tar.gz
- 切换到驱动程序src目录
# cd e1000e-3.6.0/src/
- 编译安装驱动模块
# make install
驱动模块将安装到/lib/modules/$(uname -r)//updates/drivers/net/ethernet/intel/e1000e/e1000e.ko
- 使用 modprobe 命令加载模块
#modprobe e1000e
如果之前内核里面有低版本e1000e驱动需要先卸载
#rmmod e1000e
- 安装了新驱动程序后更新initrd/initramfs,防止重启后未加载新驱动
u系系统执行
#update-initramfs -u
R系系统执行
#dracut -f
可能会遇到以下报错:(编译报错日志见附录1)
error: static declaration of ‘napi_consume_skb’ follows non-static declaration
error: redefinition of xxx
可通过查看内核头文件中该函数定义,基本上都是我们内核做了修改,偏离了标准内核,因此可以采取修改函数名称方式解决问题,例如修改
#vim /home/kylin/code/e1000e-3.6.0/src/kcompat.h +5793
static inline void _napi_consume_skb(struct sk_buff *skb,
int __always_unused budget)
{
dev_consume_skb_any(skb);
}
在函数名称前加一个下划线区别于内核已定义的函数,系统则使用内核中实现的函数完成相应功能。
- 编译raid驱动
此处以编译smartpqi驱动为示例,以及制作dd.iso 满足安装需求。以V10服务器系统为编译测试环境,版本为:Server-V10_U1-Release-Build02-20210824-GFB
驱动下载链接:https://storage.microsemi.com/en-us/speed/raid/aac/linux/smartpqi_src_v2.1.12-055_tgz.php
- 解压源码
# tar -zxf smartpqi_src_v2.1.12-055.tgz
- 安装源码包
# cd srcrpm/
# rpm -ivh smartpqi-2.1.12-055.src.rpm
- 编译源码
# cd /root/rpmbuild/SPECS
# rpmbuild -bp smartpqi-src.spec
# cd ../BUILD/
# make
- 构建rpm包
# cd ../SPECS/
#rpmbuild -ba
构建完成的包位于RPMS目录中
- 安装验证
#rpm -ivh smartpqi-2.1.12-055.ky10.x86_64.rpm
问题1:
错误:问题来源: /root/rpmbuild/SOURCES/smartpqi-2.1.12-055.ky10.tar.bz2: 没有那个文件或目录
只需要修改源码包的名字即可
#cd ../SOURCES/
#mv smartpqi-2.1.12-055.tar.bz2 smartpqi-2.1.12-055.ky10.tar.bz2
问题2:
/root/rpmbuild/BUILD/src/smartpqi_init.c:7173:11: 错误:从不兼容的指针类型初始化 [-Werror=incompatible-pointer-types]
.ioctl = pqi_ioctl,
^~~~~~~~~
/root/rpmbuild/BUILD/src/smartpqi_init.c:7173:11: 附注:(在‘pqi_driver_template.ioctl’的初始化附近)
此处报错得知驱动代码中的数据类型不对,我们可以查看系统内核头文件中源码定义
#vim /root/rpmbuild/BUILD/src/smartpqi_init.c +7173
static struct scsi_host_template pqi_driver_template = {
.module = THIS_MODULE,
.name = DRIVER_NAME_SHORT,
.proc_name = DRIVER_NAME_SHORT,
.queuecommand = PQI_SCSI_QUEUE_COMMAND,
.scan_start = pqi_scan_start,
.scan_finished = pqi_scan_finished,
.this_id = -1,
.eh_device_reset_handler = pqi_eh_device_reset_handler,
.ioctl = pqi_ioctl,
.slave_alloc = pqi_slave_alloc,
.slave_configure = pqi_slave_configure,
.sdev_attrs = pqi_sdev_attrs,
.shost_attrs = pqi_shost_attrs,
};
接下来去内核中搜索该函数的代码情况
# grep -rni "struct scsi_host_template {" /usr/src/
结果如下:
/usr/src/kernels/4.19.90-25.2.v2101.gfb01.ky10.x86_64/include/scsi/scsi_host.h:51:struct scsi_host_template {
#vim /usr/src/kernels/4.19.90-25.2.v2101.gfb01.ky10.x86_64/include/scsi/
scsi_host.h +51
可以看到ioctl的声明如下:
int (*ioctl)(struct scsi_device *dev, unsigned int cmd,
void __user *arg);
再次搜索驱动源码中pqi_ioctl 的函数定义及参数情况
#grep -rni "pqi_ioctl" /root/rpmbuild/BUILD/src/
结果如下:
/root/rpmbuild/BUILD/src/smartpqi_init.c:6648:static int pqi_ioctl(struct scsi_device *sdev, IOCTL_INT cmd, void __user *arg)
/root/rpmbuild/BUILD/src/smartpqi_init.c:7173: .ioctl = pqi_ioctl,
#vim /root/rpmbuild/BUILD/src/smartpqi_init.c +6648
可以看到该函数的实现中,cmd参数的类型与内核源码不匹配,因此修改该参数的类型即可
static int pqi_ioctl(struct scsi_device *sdev, IOCTL_INT cmd, void __user *arg)
{
int rc;
struct pqi_ctrl_info *ctrl_info;
ctrl_info = shost_to_hba(sdev->host);
switch (cmd) {
case CCISS_DEREGDISK:
case CCISS_REGNEWDISK:
case CCISS_REGNEWD:
rc = pqi_scan_scsi_devices(ctrl_info);
break;
case CCISS_GETPCIINFO:
rc = pqi_getpciinfo_ioctl(ctrl_info, arg);
break;
case CCISS_GETDRIVVER:
rc = pqi_getdrivver_ioctl(arg);
break;
case CCISS_PASSTHRU:
rc = pqi_passthru_ioctl(ctrl_info, arg);
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
修改后为static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg)
...
问题3:
执行rpmbuild -bb 构建软件包过程中还是会有问题2的报错,因为原始的源码中我们未修改,因此需要修改/root/rpmbuild/SOURCES/smartpqi-2.1.12-055.ky10.tar.bz2 包中的代码
#cd /root/rpmbuild/SOURCES/
#mkdir temp
#tar -xf smartpqi-2.1.12-055.ky10.tar.bz2 -C temp
#cd temp
#grep -rni "pqi_ioctl(" .
结果如下:
./src/smartpqi_init.c:6648:static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg)
#vim src/smartpqi_init.c +6648
修改完成重新打包
#
问题4:
处理文件:smartpqi-debuginfo-2.1.12-055.ky10.x86_64
错误:空 %file 文件 /root/rpmbuild/BUILD/smartpqi-2.1.12/debugfiles.list
RPM 构建错误:
空 %file 文件 /root/rpmbuild/BUILD/smartpqi-2.1.12/debugfiles.list
需要先修改smartpqi-src.spec (使用命令vim smartpqi-src.spec编辑,添加%global debug_package %{nil})
修改后内容如下
...
# prep ############
%global debug_package %{nil}
%prep
echo prep %{version}-%{release}
%setup -c -b 0
cp %_sourcedir/Module.supported src/Module.supported
附录1:e1000e驱动编译报错信息
make[1]: Entering directory '/usr/src/kylin-headers-4.4.131-20200710-generic'
CC [M] /home/kylin/code/e1000e-3.6.0/src/netdev.o
In file included from /home/kylin/code/e1000e-3.6.0/src/e1000.h:14:0,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:30:
/home/kylin/code/e1000e-3.6.0/src/kcompat.h:5793:20: error: static declaration of ‘napi_consume_skb’ follows non-static declaration
static inline void napi_consume_skb(struct sk_buff *skb,
^
In file included from include/linux/if_ether.h:23:0,
from include/uapi/linux/ethtool.h:17,
from include/linux/ethtool.h:17,
from include/linux/netdevice.h:42,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:13:
include/linux/skbuff.h:2354:6: note: previous declaration of ‘napi_consume_skb’ was here
void napi_consume_skb(struct sk_buff *skb, int budget);
^
In file included from /home/kylin/code/e1000e-3.6.0/src/e1000.h:14:0,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:30:
/home/kylin/code/e1000e-3.6.0/src/kcompat.h:5802:20: error: redefinition of ‘csum_replace_by_diff’
static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
^
In file included from include/linux/skbuff.h:31:0,
from include/linux/if_ether.h:23,
from include/uapi/linux/ethtool.h:17,
from include/linux/ethtool.h:17,
from include/linux/netdevice.h:42,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:13:
include/net/checksum.h:122:20: note: previous definition of ‘csum_replace_by_diff’ was here
static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/e1000.h:14:0,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:30:
/home/kylin/code/e1000e-3.6.0/src/kcompat.h:5897:1: error: redefinition of ‘pci_request_io_regions’
pci_request_io_regions(struct pci_dev *pdev, const char *name)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/netdev.c:9:0:
include/linux/pci.h:1441:1: note: previous definition of ‘pci_request_io_regions’ was here
pci_request_io_regions(struct pci_dev *pdev, const char *name)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/e1000.h:14:0,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:30:
/home/kylin/code/e1000e-3.6.0/src/kcompat.h:5906:20: error: redefinition of ‘pci_release_io_regions’
static inline void pci_release_io_regions(struct pci_dev *pdev)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/netdev.c:9:0:
include/linux/pci.h:1448:1: note: previous definition of ‘pci_release_io_regions’ was here
pci_release_io_regions(struct pci_dev *pdev)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/e1000.h:14:0,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:30:
/home/kylin/code/e1000e-3.6.0/src/kcompat.h:5917:1: error: redefinition of ‘pci_request_mem_regions’
pci_request_mem_regions(struct pci_dev *pdev, const char *name)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/netdev.c:9:0:
include/linux/pci.h:1455:1: note: previous definition of ‘pci_request_mem_regions’ was here
pci_request_mem_regions(struct pci_dev *pdev, const char *name)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/e1000.h:14:0,
from /home/kylin/code/e1000e-3.6.0/src/netdev.c:30:
/home/kylin/code/e1000e-3.6.0/src/kcompat.h:5926:20: error: redefinition of ‘pci_release_mem_regions’
static inline void pci_release_mem_regions(struct pci_dev *pdev)
^
In file included from /home/kylin/code/e1000e-3.6.0/src/netdev.c:9:0:
include/linux/pci.h:1462:1: note: previous definition of ‘pci_release_mem_regions’ was here
pci_release_mem_regions(struct pci_dev *pdev)
^
cc1: warning: unrecognized command line option ‘-Wno-misleading-indentation’
scripts/Makefile.build:277: recipe for target '/home/kylin/code/e1000e-3.6.0/src/netdev.o' failed
make[2]: *** [/home/kylin/code/e1000e-3.6.0/src/netdev.o] Error 1
Makefile:1484: recipe for target '_module_/home/kylin/code/e1000e-3.6.0/src' failed
make[1]: *** [_module_/home/kylin/code/e1000e-3.6.0/src] Error 2
make[1]: Leaving directory '/usr/src/kylin-headers-4.4.131-20200710-generic'
Makefile:73: recipe for target 'default' failed
make: *** [default] Error 2
附录2:smartpqi 驱动包编译错误日志
/root/rpmbuild/BUILD/smartpqi-2.1.12/src/smartpqi_init.c:7173:11: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.ioctl = pqi_ioctl,
^~~~~~~~~
/root/rpmbuild/BUILD/smartpqi-2.1.12/src/smartpqi_init.c:7173:11: note: (near initialization for 'pqi_driver_template.ioctl')
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:303: /root/rpmbuild/BUILD/smartpqi-2.1.12/src/smartpqi_init.o] Error 1
make[1]: *** [Makefile:1541: _module_/root/rpmbuild/BUILD/smartpqi-2.1.12/src] Error 2
make[1]: Leaving directory '/usr/src/kernels/4.19.90-25.2.v2101.gfb01.ky10.x86_64'
cp: cannot stat 'smartpqi.ko': No such file or directory
make: *** [Makefile:119: build] Error 1
错误:/var/tmp/rpm-tmp.GnWNp9 (%build) 退出状态不好