linux在x86下的启动
一、Boot部分的困惑
这一部分确实困扰了我有一段时间。不太清楚这一部分需要完成的内容。然后通过阅读Linux比较新的源码来获取灵感。同时这也使我陷入了一个更大的更多的困惑之中。之后我通过不断读源码和翻手册才大致弄去清楚。
首先是x86架构下Linux的启动。在Linux最最最早期的版本中是有自己的bootloader的,就是最开始的512字节,然后和GNU有了"py"交易,就用上了Grub,后来索性就不要这部分,但是还是保存在了内核代码中,这部分代码看起来就像是"屎山"。
跳过这段代码之后就是广为人知的初始化环境、填充启动协议要求的参数以及跳转保护模式,这样看起来没什么问题对吧。但是我当时脑子一抽,Grub启动内核不是直接进保护模式了吗?怎么还在运行实模式的代码?
看一下grub.cfg发现Linux用的是linux加载内核,我是multiboot加载的(这是Grub2的加载方式,Grub不一样)。我就猜测可能是Grub做了特别的事情吧!
在我还是迷迷糊糊的时候,看见了Linux启动协议的最后两段,32位启动协议和64位启动协议。然后就恍然大悟。
二、向后兼容的Linux启动
Linux内核提供了三种启动协议(16位、32位、64位),为的就是兼容那些还不是UEFI的机器。同样的,Grub对此也提供了相应的启动方式(只有16位和32位哈!Grub最多在32位下运行)。
下载Grub源码就可以看见linux16和linux这两条命令,那么对应的就是两种启动方式。
首先Grub加载setup和kernel到指定位置,如果是32位就直接填充zero page(手册上抄的名词)接着运行即可,但是如果是16位就要Grub就要从保护模式转为实模式也就是32位转为16位,接着把权限交给setup的部分,接着初始化环境、填充启动协议要求的参数以及跳转保护模式。
!内核的解压是内核本身完成的,也就是跳转保护模式后执行的函数。在setup部分没有加载内核的函数,所以加载文件到指定内存还是要靠bootloader。
三、至此,疑惑解决
读源码看协议本就是一件枯燥乏味的事情,但结果却是能够足以令人兴奋的。宛若看见计算机世界的神迹!