kexec–快速重启linux

linux几乎可以运行任何可以运行的东西,这好像是废话。其实这句话的意思是它可以将任何东西作为可以执行的映像来执行,内核既然也是一种elf映像,那么它当然是一种可执行的实体了。
     linux内核是宏内核,就是说linux的内核是一个整体,里面包罗万象,这看起来让人觉得linux是杂糅在一起的一堆,但是它内部的设计却是高度模 块化的,甚至是OO的,而且性能非常好,绝对不是将性能和稳定性作为容易维护的代价,linux内核从来都没有捧软件工程的场,但是它确实完全符合软件工 程的思想,原因何在?艺术,因为创造它的人把它作为艺术品,而艺术品的美绝对是一种真实美,一种纯洁美。
     linux内核的一体性使得它很容易作为一个整体被移动,加载,执行,这是很方便的,可以把特性,不足,甚至bug集中在一个一体的内核当中,而不像微内 核或者windows之类的乱内核出了问题让你找不到北。linux内核非常精巧,不但作为磁盘映象它是一体的,作为载入内存之后的内存映像,它也是一体 的,它加载到内存的固定位置,占用内存非常之小,这让内核本身可以在内存中非常灵活,灵活在哪里呢?你可以实现在运行时升级,修补,甚至替换linux内 核,替换linux实际上不就是重新启动吗?是的,就是重新启动。如今的linux内核中提供了kexec机制可以实现linux在运行时重新启动而不用 重新启动硬件。
首先我们看一下linux之所以可以实现这种特性的原因,上面已经说了其中一点,还有一点就是linux灵活的内存管理系统,内存是程序的躯体,逻辑是程 序的灵魂,因此内存直接影响着程序,当然也影响着内核,任何可以被cpu执行的执行绪都在内存中,代码来自内存,数据来自内存,一切都来自内存,而 linux操作系统运行除了依赖内存外还依赖内核,要想替换内核并且跳转到新内核,而且是在当前的内核上下文替换内核是很不容易的,因为“替换并跳转”本 身的代码要来自老的内核,在没有第三方帮忙的情况下,新内核替换了老内核之后的瞬间老内核就要失效了,那么“替换并跳转”仅仅在替换完成后就完蛋了,不能 跳转到新内核了,这正如自己永远不能举起自己是一样的道理,再者,linux是一个分页系统,页表占有举足轻重的地位,在载入新内核并跳转到它之前,如果 清空了页表,那么现在的执行绪还怎么继续下去,毕竟在替换并跳转的操作中,cpu认的还是虚拟地址,还要通过页表这一MMU设施来进行转换才可以得到物理地址的,如何绕开mmu或者主宰mmu平滑地过渡到新内核的虚拟内存就是一个问题了。
     linux自身的灵活性恰恰很简单地解决了上述问题,在linux中除了内核映像的位置是固定的外,没有什么是固定的,也就是说你可以在任何地方放置任何东西,linux仅仅规定了虚拟内存高1G的几个区域以及它们的用途,却并没有规定更具体的事情,比如什么页面必须映射到哪个地方,另外,linux对物 理内存几乎没有做任何规定。想想windows是怎么做的,页表的虚拟内存地址固定,文件映射缓存的虚拟地址固定,等等等等,几乎和linux相反,一切 都是固定,虽然固化内存的windows在内存如此廉价的今天可以用自映射技术节省了那么一点内存,但是却极大的限制了其灵活性,这点上,windows 像阵列,而linux更像太极。linux的内存内容的不受限制就是说你可以将页面映射到任何位置,而且你可以在任何地方申请得到这样页面,想替换运行中 的内核,其逻辑一想便知,将新的内核映像映射到内存的某些页面,最好是物理连续,物理不连续也行,逻辑连续就成,然后将“替换并跳转”的代码映射到某些页 面并且让这段代码“记住”新内核映像的页面,然后跳转到这个“替换并跳转”的代码并把这个代码的页面映射到与物理地址相同的虚拟地址(这并不会导致问题, 不会和内核数据或内核代码冲突,只要在3G以下就可以,用户空间这个时候已经完全没有用了,系统默认这个时候用户进程已经完全没有一个在运行了),最后跳转到这个“替换并跳转”的代码处,在这段代码中进行替换操作,实质上就是mov指令,此时禁用分页就没有问题了,因为这段代码的虚拟地址和物理地址一致, 程序继续进行而不会跑飞,最后linux采用了一个技巧,不是靠jmp指令跳转到新的内核,而是靠ret,因为在此之前,这段代码已经设置了堆栈和新内核 的起始地址并让它们在一起了,一个跳转正好过去。最后我们来看一下一些代码:

NORET_TYPE void machine_kexec(struct kimage *image)

{

         unsigned long page_list;

         unsigned long reboot_code_buffer;

         relocate_new_kernel_t rnk;

         local_irq_disable();

         reboot_code_buffer = page_to_pfn(image->control_code_page) << PAGE_SHIFT;

         page_list = image->head;

         identity_map_page(reboot_code_buffer); //此举乃是一致性映射

         memcpy((void *)reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size);

...

         rnk = (relocate_new_kernel_t) reboot_code_buffer;

         (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae); //“替换并跳转”函数

}

最后看一下最终的要执行的“替换并跳转”的汇编代码:
relocate_new_kernel:
         /* read the arguments and say goodbye to the stack */
         movl  4(%esp), %ebx /* page_list */
         movl  8(%esp), %ebp /* reboot_code_buffer */
         movl  12(%esp), %edx /* start address */
         movl  16(%esp), %ecx /* cpu_has_pae */
         /* zero out flags, and disable interrupts */
         pushl $0
         popfl
         /* set a new stack at the bottom of our page... */
         lea   4096(%ebp), %esp
         /* store the parameters back on the stack */
         pushl   %edx /* store the start address */
         movl    %cr0, %eax   ;下面禁用分页;禁用写保护;禁用对齐检测...
         andl    $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax
         orl     $(1<<0), %eax
         movl    %eax, %cr0
         /* clear cr4 if applicable */
         testl   %ecx, %ecx
         jz      1f
...
         jmp 1f
...//这里就是“替换”操作
         xorl    %eax, %eax
         movl    %eax, %cr3    ;清空cr3,这时分页已经禁用了,清空cr3只是为了刷新TLB
...//这里清空出了esp外的所有寄存器
         ret    ;这里进行跳转操作
代码看完了,这些代码仅仅是最后的代码,其实kexec本身很复杂,不仅仅是这些,还包括用户空间的kexec-tools等一些代码,强烈建议阅读之。本文仅仅讨论代码背后的东西,代码是一样的,谁看都一样,不同的是理解方式,对于理解方式就仁者见仁智者见智了,kexec的意义在哪呢?如果仅仅是美学意义,IT产业都不会发展了,其真正的意义在于它可以大大缩短重新启动的时间,在系统启动过程当中,最最耗时的就是硬件的初始化,设备的复位,自检等等,kexec跳过了这些步骤,但是可能导致的问题就是硬件可能出于未知的状态,不过这个问题不难解决,任何问题到了linux这里都不是问题,比如 linuxbios就可以替代传统的bios进行一次性的设备初始化。

原文链接: https://blog.csdn.net/dog250/article/details/5303642

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    kexec--快速重启linux

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/410015

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午11:46
下一篇 2023年4月26日 上午11:46

相关推荐