明天我们讲一下X8686Linux的启动。
一个计算机的启动,最主要就是CPU的启动。CPU启动就是把这个CPU的底下的各个寄存器设置到一个已知的、固定的状态,但是从这儿开始执行。
01表针启动
如右图的一侧这有几个就是X86的话的一些比较清晰可见的寄存器,其中最重要的是EIP,即指令表针。
指令表针就表示它要执行的下一个指令,当我们CPU一发生Reset之后,这个EIP作为一个固定的值,都会从这儿开始执行,这儿一般是BIOS的程序。
X86的CPU有三种启动方法:
加电启动和Reset十分类似,不但把左边的这种值都设到一个固定的状态,我们还把CPU其它的好多寄存器都设置到一个已知的固定的状态。
这么INIT不同呢?它仅仅是把左边的这种设置到一个固定的已知的状态,其它的寄存器它基本上保持不动。目的就是为了你启动完以后能够读原先寄存器里的东西。这种寄存器主要是记录了一些上一次启动的CPU错误状态,这样我们可以借此来做确诊。
如今说PowerOn一般称作冷启动,Reset我们一般称作热启动,它俩是基本一致,而且INIT就很不同,并且总体上来说,它还是从CPU一个固定的状态开始执行程序,X86Reset以后,它就处于一个RealAddress模式。
这个讲上去话长,由于X86的历史比较悠久,从80、86、80、88,它现今有RealAddress模式有protect模式,还有现今X8664模式,Reset以后它一定是处于RealAddress模式,每位CPU被Reset以后,它从一个固定的地方开始执行。
第一个一般是它要执行一个合同,选定一个CPU来执行,其他CPU都等待,我们要选定一个所谓主CPU(虽然它的标准术语叫BootstrappingCPU),就是说选完了以后,只有主CPU继续执行,其它都步入一个等待状态,就是等待所有的其它CPU都等待这个BSP给它发指令,它再开始继续执行。
BSP选下来以后,它就开始执行BIOS代码,这个BIOS代码一般我们又叫它POST过程,它相当于机器一个自检,当机器自检完了,BIOS走完了以后,它要做的一件事情就是要找到一个文件,但是把它读到显存里,之后开始执行它。
这个时侯我们觉得post自检完了,要开始读取并执行第一个外部程序,通常叫它BootLoad,这么它这个怎么找到并读取并执行它呢?
第一个问题主要是找到并读取它,这儿又分几种,譬如
LegacyBIOS启动
LegacyBIOS通常都从某个硬碟上启动,一般在过去这个叫C盘,由于过去只有一个盘叫C盘,如今其实c盘好多了,你还是要指定一个启动盘,从那个卡上的那个盘来启动。
假如是指定了,它就读你指定的盘,这个硬碟的同一个磁道,512字节。读进来以后,首先检测磁道的标记,标记这块盘是不是可以启动的,假如标记它不是可以启动的,这么它会报告一个错误,大约就是找不到启动盘之类。
假如标记的它是可以启动的一个硬碟,这么它还会开始执行,其实了这时侯这个磁道的内容早已在显存里了,它就开始执行从0开始一个446字节宽度的这个小程序,其实了我们看这个程序很小,所以它似乎它还要想办法,读到另外一个更大的程序,才才能把我们说的BootLoad,例如说Grub完完全全加载上去,光446字节肯定是不行的。
UEFIBIOS启动
UEFIBIOS会好一点,它显卡上记录的是一个启动文件路径,这个启动文件路径就是某个盘某个分区上面的某个文件,这个分区是哪些文件系统呢?一般它是FAT32文件系统,又叫ESP文件系统。
假如UEFI想启动,一定存在如此一个分区,它有如此一个FAT文件系统,之后在上面有某一个程序,都是写在NVRAM里头,我们称作启动项,它把那种程序读进来,执行它。
这样看UEFI肯定比Legacy要很多了。Legacy第一步你必须是446字节的那种,UEFI一下子可以把整个文件读进来,不须要分几步来做。
光碟启动
从光碟启动是如何启动呢?光碟在Legacy模式下,它有一个读一个特殊的记录,这个记录标明它是启动记录,这个启动记录可以任意的,没有过去光碟446字节的限制了。
所以说虽然虽然在Legacy模式下,从CD上启动它也要容易一些,由于它就是读固定的记录,记录一个任意大的文件,读进来直接执行。
假如在UEFI下它也是一个启动记录,而且这个记录本身,并不是一个文件,它是一个文件系统的镜像。这个文件系统有啥东西呢?可能主要有启动文件。
为何UEFI跟Legacy启动模式的不一样呢,在理论上来说它须要分辨,你是LegacyBIOS,你就读那一个记录,哪个记录就是个文件,直接读取来执行它。那假如你是UEFI,那你就找到FAT32的镜像linux关机命令,这儿面有文件,之后你把它读进来执行。
不管是Legacy还是UEFIBIOS,假如都不行,还可以从网路启动,从网路启动也是要首先要找到而且把一个启动文件读进来,这么这儿它就稍稍费力一点。
网路启动
网路启动最早功能全部写在网卡里,也就是说每位网卡厂商都自己写了一段从网路的启动的程序,之后把它烧在网卡里,后来有UEFI以后,Intel就主导制订了一个PXE合同,这个PXE似乎就是把这种网路启动要用的公共的东西,列入到了BIOS功能里。
例如说TCP-IP、TFTP、DHCP,这种东西跟网卡没有关系,网卡要做的就是收发报而已。
PXE合同分四步:
第一步,必须有DHCP,先发DHCP包,我要取得IP地址,能够做前面的事情,假如你是想启动的话,在DHCP包上面还附加了好多东西,附加了一些标记。
第二步,在包发出去以后,听到这个标记的人,假如他能提供PXE服务,也会响应关于PXE的东西。
PXE响应它哪些呢?有几个IP地址,这几个地址是可以提供启动服务的,但是每位IP地址它哪些文件,都可以告诉你。
最后一步,有了启动服务器的地址和我要启动的文件,这么我就通过TFTP从这个服务器下载这个文件就可以了。
下边这是一档事例linux运维博客,在标准的DHCP服务里,附送提供PXE支持,它支持在哪呢:首先它检视DHCP包上面是不是包含这个数组,假若包含这个数组,就告诉你启动服务器是谁,你去跟他找启动文件。
光告诉你启动服务器是谁还不行,还必须告诉你启动文件是啥,启动文件按照型号不同它是有区别的,例如你是启动PowerPC,还要启动mips,还要启动SUN的SPARC。
02启动Linux须要哪些
光是X86就有三种构架,一种是64位的UEFI,一种是32位的UEFI,另外一种就是老的i386的PC模式,称作LegacyBIOS模式。
所以依据包上面告诉我的构架不同,就反馈你文件名,不同的文件名给你,等于交互完以后就得到两个:一个是不同IP地址,一个是文件名。通过TFTP给它下载出来开始执行就好了。旁边的就跟从硬碟上是一样的了。
若果是启动Linux呢?Linux现今须要哪些东西?
Linux只须要两个东西(其实了虽然它是须要三个东西),但文件只须要两个:一个是内核文件,一个称作INITRAMFS文件。
我们都晓得内核文件肯定须要,任何一个操作系统上去都必须先把内核设置好,启动好。
INITRAMFS是一个给Linux用作根的一个文件,你们晓得Unix启动一定须要有一个根文件系统,这个Unix才才能运行。若果在内核启动的时侯,到最后找不到这个根文件系统都会启动失败。
有了INITRAMFS文件以后,Linux内核的启动过程中会展开INITRAMFS文件。这个文件或许就是一个CPIO包,它把这个包展开到它的显存里,在展开的显存里会听到目录构架,会有文件,它就到这一块区域当成它的根。
也就是说无论怎样,内核文件+INITRAMFS文件一定就能启动一个小Linux。
哪些叫小Linux,由于INITRAMFS不可能很大,通常几十兆,所以它启动上去以后,它就是一个完完全全置于显存里的Linux,它小是由于这个文件大小遭到了限制,这么内核文件加上INITRAMFS展开后,把它作为一个根文件系统,这就是一个小的全部在显存里的Linux。
麻雀虽小,脏腑俱全,有显存和输入输出,就可以做任何事情,所以它适宜做一些工具类的东西,安装肯定是也通过它就可以继续安装linux 下使用u盘,例如往硬碟上装东西或则做外设的配置修改、FW升级等,它特别适宜做一次性的工作。
我们一般用一个LiveImage来启动这样一个Linux,其实它稍稍比这个还复杂一点,而且基本上还是一个完完全全在显存里的小Linux,启动完后把U盘取走也没有任何问题。
其实我们大部份的情况下启动可能不仅仅是想启动一个内核里的小Linux。
例如当前我有一个硬碟,硬碟上放了一个很大的Linux,几十个G,想启动这个系统就按照启动Grub的参数,叫root=哪些哪些,这时侯这个小Linux都会找这个root,root找到了以后(一般它是一个硬碟上的一个分区的一个文件系统),我们给mount到一个目录下边,由于当前已有根,只不过这个根完完全全是个显存文件系统,我们可能会创建一个目录叫newroot,之后把你拟定的这个根mount到这个newroot下边。
mount好后把其它的进程都中止掉,之后把当前这个根上面的基本上所有其它文件都删除释放显存。但newroot必须保留,由于Newroot挂载的新的根文件系统,到最后就执行一个操作叫switch_root,把这个newroot变为根再执行根上面的INIT,就完成拉上去了一个新的Linux,即硬碟上的Linux。
在这儿内核启动的时侯早已固定了,也就是说我们拉上去的这个硬碟上的Linux,一定要跟我当前的内核是兼容的,这么安装完系统之后,刚开始启动的内核到最后切换到根上,拉上去的这个大的Linux一定是相同内核的,否则都会有兼容性的问题。
这就是怎样启动一个硬碟上的大Linux或在网路上的一个大Linux,或则是任何其它的诸如U盘上的Linux环境你也可以给它拉上去。
其实假如在U盘上的Linux我建议你直接用全部在显存里的Linux,没必要再拉一次在网路上的或则是在硬碟上的。INITRAMFS不可能放得下所有东西。
通常还有一个二次的,就是拉上去Linux在中间的过程,可以说基本上不仅内核没变,其它的环境都变掉了,这就是启动一个完整的Linux。
03另类的启动:KEXEC
下边我们介绍一下另类的启动。
Linux还有一种启动方法称作KEXEC,KEXEC原本是一个Linux的内核的这个开发者,由于她们时常更改内核,更改完了以后要重启瞧瞧,每一次重启都要经过一个CPU的Reset的冷启动也好,热启动也好,那是很苦闷的事情。
由于Reset这个CPU以后一定先走BIOS,BIOS走完了最后走Grub,最后有个BootLoad,Grub走完了才启动Linux,由于嫌这个很烦,她们就开发了一个东西,就是在当前的Linux下,我突发奇想,想换一个新内核,他就用这个KEXEC先把一个内核加进来之后跳转到新内核里,相当于执行了一次Linux重启,并且注意跳过了上面的POST和Grub。
这就是这位开发人员懒就开发了一个这个功能,这个功能确实能省好多时间。
假如你要想让内核能否如此加载的话就有一个要求,要求PositionIndependentCode这段代码可以再任意加载到任意地址,假如不能加载到任意地址的话,就要求固定地址。
那在当前内核怎么加载另外一个内核?跟冷启动一样貌似有三样东西,一个是内核文件,先把它加进来,之后INITRAMFS文件也加进来,之后启动参数主要是指根,总的来说这个KEXEC是一个十分奇妙的启动Linux形式。你们可以试一下在自己Linux上用它来试一下。
04Linuxkdump模式
最后我们要讲一下Linuxkdump模式,紧密依赖KEXEC的模式的dump十分重要。
dump是哪些?
就是应用CRASH掉的时侯,应用当时占的显存的所有的内容,之后剖析应用在那里CRASH掉了。系统也一样,当Linux系统出了某种错误,哪怕是硬件出了某种错误进行不下去的时侯如何确诊它,我们须要把它当前的显存的内容全拷贝出来。
怎么拷贝呢?
在CRASH的时侯,假如没有kdump来支持,CRASH就hung在那了,若果启动了kdump,在启动内核,生产系统内核的时侯,有一个参数叫Crashkernel,Crashkernel等于多少多少,就是预留一块显存给这个kdump的kerneldump内核轮询用。预留完后,当生产系统上去,它的一个服务就是把kdump所用的内核加载到这块预留的区域里。
为何要这样做呢?
由于系统CRASH的时侯再加载内核似乎有问题,虽然CRASH这种问题啥都做不了,内核早已无法加载了,动都动不了了,就一定要在生产系统刚起的时侯预留一块区域,这块区域谁都不能使用,之后把一个内核加在上面,INITRAMFS加在上面,这些参数也加在上面,这样当这个生产内核跳着跳着要CRASH了,若果这个区域都设置好了它还会直接跳转到这个区域里新的内核里,开始新的内核新的一个Linux环境的启动。
这个Linux环境会限制在预留的区域里,在预留的区域里启动完以后,它要做的事情就是第一,把前一个环境的诸如说100个G也好200个G也好的内容拷贝下来,拷贝到指定的某一个c盘的目录下,这就是kdump。
Kdump确实是十分好的看法,它依赖于KEXEC,KEXEC是一个快速的Linux启动linux 下使用u盘,好多程序员不耐烦那种POST的过程太长,Kdump挺好的解决了这个问题。