• linux kexec内核引导


    linux kexec 介绍

    kexec的功能是用一个运行的内核去运行一个新内核,就像运行一个应用程序一样。这种机制因为跳过了bootloader,可以实现系统的快速重启。另外kdump也是基于kexec实现(示意如下)。

    kexec的实现有几点难点:

    1. 在当前内核的上下文中,如何用新内核去替换现有内核?
    2. 正常复位启动过程中,设备会被复位(或初始化)到已知状态。跳过了复位阶段,那如何在新内核kexec启动时,保证设备状态的可靠?

    kexec的使用示例如下,其分为2部分:kexec内核加载和kexec内核执行。

        kexec -l /bzImage --initrd=/initrd.img.gz --append="ro nosmap loglevel=4 console=ttyS0,9600n8 acpi_rsdp=0x7b7fe014"
        kexec -e

    kexec 内核加载

    1. 将内核镜像文件、根文件系统、命令行参数等segment加载到用户态内存;
    2. 对segment sha256检查,确保内核数据没有被破坏;如果是kdump,备份相关数据到备份区(如i386,最开始的640K配置数据用于SMP内核启动,需要备份;或者powerpc,固定位置的异常向量等信息需要备份等)。这个环节又叫purgatory,其流程可以在用户态控制实现,也可以在内核态控制实现(如使能--kexec-file-syscall选项);
    3. 分配内核态页面,并将segment从用户态内存copy到内核态页面;如果使能--kexec-file-syscall选项,则跳过前面两步,直接将segment加载到内核页面,并进行purgatory。
    4. 分配页面并初始化image->control_code_page,对其建立页表,为下一步进行覆盖当前内核时代码寻址的页表映射。初始化LEVEL4/3/2/1 4层页表,并建立映射关系(如下图所示)。

    kexec 内核运行

    1. 调用设备驱动shutdown接口关闭设备;
    2. 关闭中断,如IO-APIC, local irq, LAPIC;
    3. 关闭非0号CPU核;
    4. 清空TLB(此处以下代码为汇编实现,具体实现与arch相关,一般名叫relocate_new_kernel);
    5. 设置段寄存器、gdt、idt等;
    6. 建立一个新栈,并将新内核的入口地址压入栈中;
    7. 设置cr0寄存器:使能分页功能和页面保护功能;
    8. 设置cr4寄存器:使能扩展地址;
    9. 设置cr3寄存器,使cr3指向新的页表根目录;设置后,从此就与旧内核bye bye了;
    10. 将内核segment页面copy到指定位置,覆盖当前内核;
    11. 调用ret指令,从栈中弹出之前压栈的新内核bzImage入口地址,进入新内核引导;

    kexec 调试注意事项

    1. kexec不会同步或卸载文件系统,此过程需要用户来保证;
    2. 从上面的流程中可以看出,kexec不会对cpu或设备进行复位,但系统重启过程中会调用reboot_notifier_list,所以register_reboot_notifier注册的接口不要有执行CPU复位等操作;
    3. 为了保证设备在kexec时处于稳定状态,kexec会调用设备驱动的shutdown接口来关闭,确保用户自己的设备驱动提供了正确的shutdown接口,或用户通过其他方式进行关闭;

    --EOF--

  • 相关阅读:
    【洛谷P2860】冗余路径
    【CF1042D】Petya and Array 离散化+树状数组
    【洛谷P2127】序列排序
    【洛谷P4462】异或序列
    【SPOJ10707】COT2
    【CF1119D】Frets On Fire
    【CF1119E】Pavel and Triangles
    【洛谷P1903】数颜色
    hdu 3488(KM算法||最小费用最大流)
    hdu 1853(拆点判环+费用流)
  • 原文地址:https://www.cnblogs.com/wahaha02/p/7152796.html
Copyright © 2020-2023  润新知