为树莓派编译Kdump kernel
本文记录一下编译带Kdump功能的内核的过程中需要注意的点。首先要说的是,目前Pi的Linux Kernel对Kexec的支持还有些不稳定,对于各种设备的驱动的支持还有些问题,导致整个流程不稳定。目前仍然在漫长的解决过程中:
对应的Issue的地址在这里:
https://github.com/raspberrypi/linux/issues/27
有兴趣的小伙伴可以关注下这个issue的解决情况。
虽然这个功能目前还极其不稳定的状态,但是并不影响我们通过编译过程理解内核的配置方法。
关于内核的编译与交叉编译方法,之前写的三篇文章已经有介绍,这篇文章不再重复。本文的重点是要对编译内核前的配置做下介绍。
配置内核,最稳妥的方法是在kernel的source tree下执行menuconfig
:
$ make menuconfig
如果是交叉编译,需要添加平台选项,具体参考这篇文章:
https://www.raspberrypi.org/documentation/linux/kernel/configuring.md
执行menuconfig
,会进入到kernel的配置菜单:
需要注意的是,这个配置菜单里面,有很多选项是互相制约,互相依赖的。比如:你选了A选项,那么可能B选项就不可以再被勾选。或者:你必须选择了X选项,Y选项才会出现。
这个依赖关系,在menuconfig里面是不会出现的,而是在内核的Kconfig文件里体现。
Kconfig文件在内核的每一级目录里面都存在,并且配置了各种内核编译选项,以及选项之间的依赖关系。下面是内核源码中的各个Kconfig文件:
$ find . | grep Kconfig$ | head
./usr/Kconfig
./block/partitions/Kconfig
./block/Kconfig
./certs/Kconfig
./lib/xz/Kconfig
./lib/fonts/Kconfig
./lib/Kconfig
./kernel/gcov/Kconfig
./kernel/irq/Kconfig
./kernel/power/Kconfig
可以看到,每一层目录里面都有Kconfig
文件,整体形成一个树形结构。
因此,读懂Kconfig文件,是配置内核编译选项的关键所在,建议大家阅读相关文档进行系统学习。以下是推荐阅读的一些资料:
https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
https://www.linuxjournal.com/content/kbuild-linux-kernel-build-system
对于编译Kdump内核,我们需要的关键内核选项是:
CONFIG_DEBUG_INFO
CONFIG_CRASH_DUMP
CONFIG_PROC_VMCORE
关于上面选项的相关文档在这里,供大家参考:
https://wiki.archlinux.org/index.php/Kdump
另外,在文档里没有写的是,我们还需要打开KEXEC
选项。
Linux kernel里面,CONFIG_PROC_VMCORE
是和CONFIG_CRASH_DUMP
,所以可以不用操心(分析过程接下来给出)。因此我们需要自己设置的选项是:
DEBUG_INFO
CRASH_DUMP
KEXEC
这几个选项的依赖关系,我们可以在内核代码中检索一下。我们首先检索KEXEC
选项。
因为我们是要给arm
架构平台来做编译,因此要在架构目录里进行搜索:
[weli@2ac1fbd74634 arm]$ pwd
/home/weli/linux/arch/arm
使用下面的脚本在平台目录里搜索一下KEXEC
:
for f in $(find . | grep Kconfig)
do
grep -n 'KEXEC' ${f}
RESULT=$?
if [ ${RESULT} -eq 0 ]; then
echo ${f}
fi
done
得到结果如下:
可以看到,只有./Kconfig
这个文件里面包含KEXEC
选项。于是我们打开这个配置文件,找到相关的配置选项:
可以看到它的依赖关系:
depends on (!SMP || PM_SLEEP_SMP)
这里面有一个重要信息,就是!SMP
这个条件,也就是说,只有SMP
选项不打开的时候,才能够在配置的时候选择KEXEC
选项(后面的PM_SLEEP_SMP
本文不讨论了,因为分析方法是一样的)。
我们用相同的搜索方法找到SMP
选项,并查看选项描述:
可以看到这个选项对应menuconfig
的菜单描述:
bool "Symmetric Multi-Processing"
如果我们网上看,就可以看到,这个选项位于Kernel Features
这个菜单里面:
因此,我们进入menuconfig
里面,要关掉相关的选项,然后KEXEC
对应的选项才能显示出来。
我们可以验证上面的分析,重新进入menuconfig,查看Boot options
里面的选项(也是通过分析Kconfig文件,可以得知KEXEC
选项在Boot options
的菜单里):
可以看到只有kdump
的选项,并没有相关的kexec
的选项。此时我们回到主菜单,然后按照之前的分析,进到Kernel features
里面,并且关掉Symmetric Multi-Processing
的选项:
此时重新查看Boot options
:
可以看到kexec的相关选项出现了。我们把这个选项和kdump的选项都够选上,选择菜单底部的Save
,把内容保存进.config
,并退出menuconfig。
此时比对新的.config
和原始的版本(原始版本的.config
,我之前保存为.config.org
,用于比对):
[weli@2ac1fbd74634 linux]$ diff --unified=0 .config.orig .config
--- .config.orig 2018-06-16 12:34:42.321735961 +0000
+++ .config 2018-06-16 14:07:00.601815577 +0000
@@ -30,0 +31 @@
+CONFIG_BROKEN_ON_SMP=y
@@ -75,2 +75,0 @@
-CONFIG_ARCH_HAS_TICK_BROADCAST=y
-CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
@@ -105 +104 @@
-CONFIG_TREE_RCU=y
+CONFIG_TINY_RCU=y
@@ -108 +107 @@
-CONFIG_TREE_SRCU=y
+CONFIG_TINY_SRCU=y
@@ -110,2 +109,2 @@
-CONFIG_RCU_STALL_COMMON=y
-CONFIG_RCU_NEED_SEGCBLIST=y
+# CONFIG_RCU_STALL_COMMON is not set
+# CONFIG_RCU_NEED_SEGCBLIST is not set
@@ -116 +114,0 @@
-CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
@@ -133,2 +130,0 @@
-CONFIG_CPUSETS=y
-CONFIG_PROC_PID_CPUSET=y
@@ -212 +207,0 @@
-CONFIG_SLUB_CPU_PARTIAL=y
@@ -215,0 +211,2 @@
+CONFIG_CRASH_CORE=y
+CONFIG_KEXEC_CORE=y
@@ -357,3 +353,0 @@
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-CONFIG_RWSEM_SPIN_ON_OWNER=y
-CONFIG_LOCK_SPIN_ON_OWNER=y
@@ -490 +484 @@
-CONFIG_SWP_EMULATE=y
+# CONFIG_SWP_EMULATE is not set
@@ -491,0 +486 @@
+# CONFIG_CPU_DCACHE_DISABLE is not set
@@ -503 +497,0 @@
-CONFIG_ARM_ERRATA_643719=y
@@ -506,2 +499,0 @@
-# CONFIG_ARM_ERRATA_754327 is not set
-# CONFIG_ARM_ERRATA_764369 is not set
@@ -509 +500,0 @@
-# CONFIG_ARM_ERRATA_798181 is not set
@@ -538,5 +529 @@
-CONFIG_SMP=y
-CONFIG_SMP_ON_UP=y
-CONFIG_ARM_CPU_TOPOLOGY=y
-# CONFIG_SCHED_MC is not set
-# CONFIG_SCHED_SMT is not set
+# CONFIG_SMP is not set
@@ -544,2 +530,0 @@
-# CONFIG_MCPM is not set
-# CONFIG_BIG_LITTLE is not set
@@ -551,2 +535,0 @@
-CONFIG_NR_CPUS=4
-# CONFIG_HOTPLUG_CPU is not set
@@ -591,0 +575 @@
+CONFIG_NEED_PER_CPU_KM=y
@@ -627 +611,2 @@
-# CONFIG_CRASH_DUMP is not set
+CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
@@ -653 +637,0 @@
-CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
@@ -659 +642,0 @@
-# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set
@@ -1273,3 +1255,0 @@
-CONFIG_RPS=y
-CONFIG_RFS_ACCEL=y
-CONFIG_XPS=y
@@ -1281 +1260,0 @@
-CONFIG_NET_FLOW_LIMIT=y
@@ -1509 +1487,0 @@
-CONFIG_GENERIC_ARCH_TOPOLOGY=y
@@ -5604,0 +5583 @@
+CONFIG_PROC_VMCORE=y
@@ -5837 +5815,0 @@
-# CONFIG_DEBUG_PER_CPU_MAPS is not set
@@ -5890 +5867,0 @@
-CONFIG_RCU_CPU_STALL_TIMEOUT=21
@@ -6052 +6028,0 @@
-# CONFIG_CRYPTO_PCRYPT is not set
@@ -6244 +6219,0 @@
-CONFIG_CPU_RMAP=y
可以看到,虽然我们只更改了3个选项,但是上面却有几十处连锁反应的修改,这些联动修改都是通过判断Kconfig中的依赖关系来完成的。
至此为止,我们还需要打开kernel的debug info选项。按照上面的方法分析Kconfig即可。为了方便分析,我们可以把上面用到的脚本改进一下,并且形成一个脚本文件:
[weli@2ac1fbd74634 linux]$ pwd
/home/weli/linux
[weli@2ac1fbd74634 linux]$ cat find_opt.sh
#!/usr/bin/env bash
for f in $(find . | grep Kconfig)
do
grep -n "config ${1}" ${f}
RESULT=$?
if [ ${RESULT} -eq 0 ]; then
echo ${f}
fi
done
这样,我们可以用上面的文件进行对Kconfig文件一族的分析:
$ ./find_opt.sh 'DEBUG_INFO'
140:config DEBUG_INFO
153:config DEBUG_INFO_REDUCED
166:config DEBUG_INFO_SPLIT
181:config DEBUG_INFO_DWARF4
./lib/Kconfig.debug
可以看到,相关的配置是在Kconfig.debug
里面。因此,我们重复上面的分析过程,找到DEBUG_INFO
所在的menu item和相关的依赖关系,进行配置。
在这里直接给出分析结果,这个选项是在Kernel hacking
这个条目里:
进到这个menu item里,找到Compile-time checks and compiler options
:
进到上面这个menu item里,勾选Compile the kernel with debug info
:
配置完成后,存盘推出menuconfig,检查.config
中的DEBUG_INFO
已经正确配置:
$ grep 'DEBUG_INFO=' .config
CONFIG_DEBUG_INFO=y
检查我们要的这个选项即可,其它相关的依赖会自动解决,不用操心。
以上配置全部完成后,就可以rebuild kernel了:
编译和安装内核的过程,在之前的几篇文章已经详细介绍过了,这里就不再展开了。此外,这篇参考文章要仔细读:
https://www.raspberrypi.org/documentation/linux/kernel/building.md
此外,以下有一个重要注意事项:
如果你使用交叉编译,一定要用Raspberry Pi的tools工具包里最新的gcc:
注意上面的arm编译包里,这个arm-rpi-4.9.3-linux-gnueabihf
是最新的。可以在自己的.bashrc
环境文件里配置好:
$ cat ~/.bashrc
PATH=$PATH:/home/weli/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/
上面这样,确保交叉编译工具使用最新的版本。关于这个交叉编译器版本的问题,可以查看这个相关issue:
https://github.com/raspberrypi/tools/issues/52
等编译完成后,也是按照之前文章里面介绍过的流程,把内核和编译出来的模块都安装好:
最后就是把kernel文件和设备树文件都拷贝到指定位置:
[weli@2ac1fbd74634 linux]$ sudo cp arch/arm/boot/zImage /mnt/arch/boot/kernel7.img
[weli@2ac1fbd74634 linux]$ sudo cp arch/arm/boot/dts/*.dtb /mnt/arch/boot/
[weli@2ac1fbd74634 linux]$ sudo cp arch/arm/boot/dts/overlays/*.dtb* /mnt/arch/boot/overlays/
[weli@2ac1fbd74634 linux]$ sudo cp arch/arm/boot/dts/overlays/README /mnt/arch/boot/overlays/
以上编译全部完成之后,就可以重启树莓派,使用新的,带有Kdump的内核了。
本篇文章就介绍到这里,关于如何使用Kdump,我会开一篇新的文章专门介绍。