Kexec 引导内核内幕

2019-07-13 07:09发布

class="markdown_views prism-atom-one-light">

前言

Linux 的引导流程,基本可以概括为两个阶段:分别是启动引导程序阶段以及引导程序引导启动内核阶段。
在嵌入式Linux中,第一个阶段常见的引导程序分别有bootloader/xloder/pmon/类bios等,以bootloader为例子,光开源的bootloader就有很多种,其中最出名的当初u-boot. 但是不管上述有多少种类的引导程序,其功能基本都是初始化硬件[自检等等],向内核传参。为引导内核做准备。
有差异的大多可能都在初始化DRAM前后。这里不去做深入研究。
第二阶段是引导程序引导内核,之后将控制权交给内核,内核启动流程请看start_kernel。加载驱动程序,执行执行1号进程,初始化用户态相关程序,挂载文件系统。设置其它一些要求等等。 那么在系统重启的流程,则相反,先停止相关任务[进程],将cache中的内容会写硬盘。然后重启硬件,启动的过程中都需要重新执行一次上述的流程。 在一些工作站以及服务器中,重启是一个非常缓慢的过程,因为往往时间都被消耗在了第一个阶段,对于硬重启显然是没问题的,因为掉电重启必须要保证硬件的可靠性。但是对于软重启,其实可以省略掉这些。因为有很多场景下是有这样的需求。比如:
  1. 软件异常重 - 如果可以做到重启后不重新初始化硬件,尤其是DRAM,那么内存中我们可以通过制定的划分,将上次异常的信息保存起来,用来下次分析上次异常的原因。 基于此需求,诞生了 - KDUMP.
  2. 内核热补丁 - 想想如果一台服务器正在跑关键的业务,但是确被开发者告知存在很严重的bug? 传统的流程肯定是升级版本然后重启生效,重启意为着需要业务的断掉以及等待业务的恢复,在一些场景中等待是可怕的。为此基于此场景出现了热补丁技术。诞生了-kGraft,kpatch.
以上场景技术中都提到了至为关键的一点,重启的过程中不能在重头开始,需要跳过第一个阶段,也就是一个运行的内核引导一个新的内核。
只要能实现这个功能,那么上述场景将不攻自破。 基于此需求,我们迎来了我们此文的猪脚Kexec

基本概念

Kexec 是可以在运行的内核引导另一个内核的工具,包括了kexec-tools 以及kexec Driver两部分。
kexec-tools 是一个用户态工具集,包括了kexec,vmcore-dmesg,kdump等。程序 kexec 主要功能是加载一个新的内核镜像到内存中。
并且可以传参数。

基本用法:

  • kexec -l –append=””
    在这里, 是您想要重新启动后的内核文件, 容纳的是需要传递到新内核的命令行参数。由于错误的命令行选项可能会在重新启动时引发问题,所以,确保合法值传递到重新启动的内核的安全方法是传递 /proc/cmdline 的内容。
  • kexec -e
    系统将加载新的内核并运行。

Kexec 如何引导内核

Driver 部分主要包括了arch/下架构相关的代码,以及kernel/kexec.c 公共代码。
上述说了Kexec 包括了两部分,下面我们来看看Driver部分。
Kexec 加载的大致思路是这样的:
a.将一个”新”内核COPY到内存中
b.将这个内存映像COPY到Kenry Entry的入口地址,重新执行Entry Point,进而重新运行新内核。
在分析上述两个步骤前,我们先来了解 我们先来分析公共代码,也就是用户程序的传参流程。

加载到内存

运行新内核的完成跳转

由于体系架构不同,甚至同架构但是是CPU型号不同,所以跳转细节流程是有差异的。这里分析2款主流MIPS平台CPU以及一款x86CPU

Kexec 技术应用场景

Kexec 技术展望