需求:我的网卡驱动在加载时,需要两个elf格式的固件。SDK的做法是将这两个固件放置到跟文件系统中的/lib/firmware目录下,内核启动的时候在根文件系统中寻找。这样做,内核和根文件系统就出现了一个强相关的关系。客户提出,在内核不要和根文件系统较强联系,不要出现这种情况:编译出的kernel和此根文件系统启动后,OK没有问题!!!而换了一个根文件系统,居然网络都不能用了!!!
根据客户的需求,我将SDK的elf固件编译进内核。
那么问题来了。。。如何elf固件编译进内核??
打开内核源码,在顶层目录中,有一个名为firmware的目录,对就是它就是那个固件目录。
在此目录下,有很多hex文件,这些文件都不是源码文件,那这些文件是做什么用的楠?
阅读/firmware/Makefile,我们可以知道kernel中已有的编译固件到内核的方法是(如dd.fw.hex):通过dd.fw文件生成相应二进制固件文件,将对应二进制文件通过quiet_cmd_fwbin规则包含进dd.fw.S文件,将dd.fw.S文件编译成对应的dd.fw.o文件,链接进内核镜像中。
那么这下来将两个elf文件编译进内核(a.elf, b.elf)。理清了上面原理,我们可以很容易的将elf文件编译进内核。
fw-shipped-y = a.elf , b.elf
通过上面的一行makefile语句,将a.elf b.elf编译进内核。
到这里就接受了么?
你会发现一个奇怪的问题:每次make ARCH=xxx CROSS_COMPILE=xxx clean 或者distclean后,这两个elf都会被删除!再次编译编译失败:a.elf not found。
因为我们将之定义为目标,在每次make clean时都会将生成目标全部删除,内核中其他的目标都是通过ihex文件生成,所以删除了无关紧要,而我们的elf文件,删除了就没有了。a.elf -> a.o 过程依赖a.elf。a.elf文件不存在出现编译失败!
解决的方法很简单:clean 或 distclean 不将elf文件删除!
在/firmware/Makefile文件添加下面行:
no-clean-fils=a.elf b.elf
现在clean 或 distclean时,将不会删除elf文件。
我们再次深入,你将会发现还有问题:make ARCH=xxx CROSS_COMPILE=xxx O=$(dir) 编译失败,错误还是为:a.elf b.elf not found (解决此问题需要对此Makefile有一定的深入了解)
a.elf 编译进内核的路径为:a.elf -> a.S -> a.o -> vmlinux
dd.fw 编译进内核的路径为:dd.fw.ihex -> dd.fw -> dd.fw.S -> dd.fw.o -> vmlinux
这两个文件编译进内核的方式,除了第一步就没有其他的区别!对!就是第一步导致编译的失败!
make 的O= (dir)