在为android编译ko包并使用insmod加载过程中遇到两个问题,记录如下。

【问题一:KERNEL_DIR、系统平台、交叉编译器的指定】
android编译ko包实际与linux编译ko没有区别,首先编写.c .h文件等,之后编写makefile文件,makefile中KERNEL_DIR为kernel编译后产生的临时文件夹的目录,有些系统工程会重定向生成的内核临时文件目录,所以不能简单的吧KERNEL_DIR定义为kernel源文件目录。而是应该确定生成的临时文件的目录后使用临时文件目录。

例如本次使用的工程(高通平台)就与之前的工程(联芯平台)不同,编译后的临时文件目录为out/target/product/xxxxxx/obj/KERNEL_OBJ/。所以设置KERNEL_DIR := xxx/out/target/product/xxxxxx/obj/KERNEL_OBJ/。
另外,在编写编译选项时本次的工程并没有在顶层makefile里指定使用的系统平台等,所以编译指令里需要添加上对系统平台的指定,以及交叉编译器的使用。最终使用的Makefile文件如下:

#********高通平台设备驱动Makefile******** 

CROSS_ARCH:=ARCH=arm CROSS_COMPILE="$(ARM_EABI_TOOLCHAIN)/arm-eabi-" 

KERNEL_DIR:=$(ANDROID_PRODUCT_OUT)/obj/KERNEL_OBJ/ 

PWD:=$(shell pwd) 


#这里模块名为scull 

obj-m += scull.o 

scull-objs:= main.o pipe.o access.o 


.PHONY: modules package clean 

all:package 

modules: 

    @if [ "$(ANDROID_BUILD_TOP)_yes" = "_yes" ]; then echo "You have to run \". build/envsetup.sh\" to init enviroment first. \nAnd then you have to run \"choosecombo\" to setup the project."&&exit 1; fi 

    @if [ ! -d $(KERNEL_DIR) ]; then echo "Build kernle first."&&cd $(ANDROID_BUILD_TOP)&&make bootimage&&cd -; fi 

    $(MAKE) $(CROSS_ARCH) -C $(KERNEL_DIR) M=$(PWD) modules 


package:modules 

    @mkdir -p ./package 

    @cp $(obj-m:.o=.ko) ./package 


clean: 

    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers package 


#********联芯平台的设备驱动Makefile******** 

EXTRA_CFLAGS += $(DEBFLAGS) 

EXTRA_CFLAGS += -I$(LDDINC) 


ifneq ($(KERNELRELEASE),) 

# call from kernel build system 

scull-objs := main.o pipe.o access.o 

obj-$(CONFIG_SCULL) := scull.o 

else 

# KERNELDIR ?= /lib/modules/$(shell uname -r)/build 

KERNELDIR ?= /home/zhouxiang/work/mpe168/android-4.4.4_r2/kernel/linux-3.10 

PWD       := $(shell pwd) 


modules: 

    $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules 

endif 


clean: 

    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 


depend .depend dep: 

    $(CC) $(CFLAGS) -M *.c > .depend 


ifeq (.depend,$(wildcard .depend)) 

include .depend 

endif



【问题二:模块驱动文件的签名】
编译生成module.ko后,push到android设备的system/bin目录,在insmod module.ko时提示:
insmod module.ko
insmod: init_module 'module.ko' failed (Required key not available)

根据提示应该是key的问题,查阅资料发现Linux从3.n(具体版本不清楚)开启了对加载的module进行签名认证的功能在这个功能使能之后,内核只允许安装特定的key签名的模块。
内核配置项(所在文件:kernel/kernel/Makefile)中:
CONFIG_MODULE_SIG=y
表示开启了签名机制,但是这时候模块签名或不签名都可以使用。

CONFIG_MODULE_SIG_FORCE=y
如果上述配置项使能,则模块必须有正确的签名才能正常使用。

CONFIG_MODULE_SIG_ALL=y
内核在编译的时候,并不会主动去给模块签名,除非你把上述配置项打开。查看内核配置文件,发现上面3个配置项确实都打开了,因此肯定是ko签名的问题。


如何为ko包签名呢?
首先,找到signing_key.priv signing_key.x509文件(在out/target/product/xxxxxx/obj/KERNEL_OBJ/目录下),拷贝到module源码目录。
然后,对module.ko进行签名,使用命令:
perl ../../xxxx/kernel/scripts/sign-file sha512 signing_key.priv signing_key.x509 module.ko
签名后查看签名信息,执行命令:hexdump -C module.ko | tail
00043680  9b 6f d3 d2 f6 71 27 15  73 38 d6 7b c1 c5 04 fb  |.o...q'.s8.{....|
00043690  a7 16 4c 19 01 76 b8 a5  de 90 b4 0a 10 db aa 2f  |..L..v........./|
000436a0  23 f4 97 5c a0 ce 70 c5  eb 87 95 92 5c e3 17 fd  |#..\..p.....\...|
000436b0  ef 88 9b 3e 0b db 78 38  ac ee 9c b7 ef 82 ba 97  |...>..x8........|
000436c0  24 a9 6a 7a e4 5e 75 a6  d3 9a 98 5f 50 1d 77 28  |$.jz.^u...._P.w(|
000436d0  9e 11 26 48 bb cd 79 51  82 26 05 fb 61 01 06 01  |..&H..yQ.&..a...|
000436e0  1e 14 00 00 00 00 00 02  02 7e 4d 6f 64 75 6c 65  |.........~Module|
000436f0  20 73 69 67 6e 61 74 75  72 65 20 61 70 70 65 6e  | signature appen|
00043700  64 65 64 7e 0a                                    |ded~.|
00043705
此时签名正确
最后,安装设备驱动文件。若又提示
insmod module.ko
insmod: init_module 'module.ko' failed (Required key not available)
重新编译了一次kernel镜像,并对设备fastboot flash boot boot.img重新烧录kernel镜像,再进行push, 而后insmod此次模块加载成功。

总结签名失败问题:
解决方案:
1、关闭内核的模块签名校验问题
2、使用当前内核的签名对模块进行签名 (每次编译后签名秘钥对会更新,所以在对上个版本或者更早之前的版本或者其他机器编译的内核镜像加载模块时,需要重新烧写模块编译时的当前内核镜像,这样才不会出现签名仍然不一致问题。)