无论是Linux还是Windows,在加电后的第一步都是先运行BIOS(Basic Input/Output System)程序——不知道是不是所以的电脑系统都是如此。BIOS保存在主板上的一个non-volatile(即非易失)存储器,如PROM,EPROM,Flash等。——以前的BIOS一般都是只读的,现代的系统中,允许刷新BIOS程序。它的任务就是简单的初始化和识别系统硬件设备,如CPU,内存,输入/输出设备,外部存储设备等。然后找到bootloader的位置,并加载bootloader,将PC的控制权交给bootloader,完成后面的复杂的系统初始化任务。
但是在系统启动之前,系统如何启动BIOS呢?所以系统启动的过程,也被称为自举。虽然没有“先有鸡还是先有蛋”那么复杂,但是这里也有一个矛盾。PC是这样解决这个问题的。将CPU设计成加电以后,就从一个特殊的固定的地址开始执行指令,那么BIOS的位置就放在这里,也就是存储BIOS的ROM的起始地址就是这个固定的地址,用以保证BIOS程序可以在加电时被直接执行。

这里有两个问题:
1. BIOS的存储器地址如何决定的?
2. 现在多处理器的情况下,BIOS是如何执行的?

下面以Intel CPU为例,简单说明一下流程:
Intel在初始化的时候将CPU分为两类,即BSP(Bootstrap Processor)与APs(Application Processors)。从名字上既可看出两类CPU的作用。在启动的时候,首先由硬件动态选择一个总线上的CPU为BSP,那么剩下的CPU则都为AP。由BSP执行BIOS程序,初始化环境以及APs,然后还是有BSP执行操作系统的初始化代码。
Intel CPU的第一条语句的固定地址为0xFFFF FFF0,然后BIOS的存储器被hard-map到这个内存地址。这样当CPU开始执行时,实际上执行的就是BIOS程序。

由于BIOS的存储器不会太大,所以程序一般不会太复杂,那么不大可能实现加载操作系统的操作,只能完成简单的初始化工作。这时,只能借助于外部存储器了。可是外部存储器的读取是依赖于文件系统的。而BIOS程序既然比较简单,那么是不可能去支持文件系统的,更何况有各种各样的文件系统,不可能去一一支持。这时,还是只能依赖于硬编码,必须定义一个固定的外部存储器的地址——硬盘的第一个扇区的512字节——被称为MBR(Master Boot Record)——为什么是512字节呢?按照我的理解,一般情况下一个扇区都被设置为512字节,而硬盘操作的最小单元即为一个扇区。虽然可以设置更大的扇区,但是作为一个统一的程序来说,使用惯例512是一个不错的选择。

BIOS的最后一项任务就是将MBR读入到内存中,且起始地址固定为0x7c00,然后对MBR的最后两个字节进行验证,必须为0x55和0xAA,以保证这512字节为MBR。验证通过后,则跳转到0x7c00处开始执行。这样MBR就开始执行。——这里,我有两个问题,为什么是7c00和0x55和0xAA呢?目前没有找到当初选择这两个值的解释。我依稀记得选择0x55,0xaa是因为这个值比较特殊,利于校验,但是为什么利于校验却不记得了。

MBR保存了分区表(MBR并不存在于任何一个分区中,而是处于分区之上),以及一个用于装载操作系统启动程序的小程序。MBR首先会确定活动分区,然后使用BIOS将这个活动分区的启动扇区——仍然是第一个扇区512字节,最后跳转到加载该启动扇区的内存地址处。这样就将PC的控制器转移到这个启动扇区的程序手中(即真正的bootloader)。一般来说,这个启动程序也要求被加载到0x7c00这个地址。可是这个地址之前已经加载了MBR,如果再加载这个启动程序,那么必然冲突。所以MBR实际上在开始的时候,先对自己做了relocate,将自己拷贝到另外一个地址,然后从那个地址开始执行,这样就避免了冲突。

下面就进入了真正的bootloader了,对于Linux来说,一般就是LILO和GRUB,下面以最常用的GRUB为例。

GRUB的启动分为三个阶段stage1,stage1.5和stage2,这三个阶段也被分为三个文件(在某些情况下,可以没有stage1和stage1.5)。其中stage1可以嵌入到MBR中,即MBR的头446个字节(后面为分区表64字节,0x55和0xAA两个校验字节),也可以存储在活动分区的第一个扇区512字节,
然后由MBR来加载。所以stage1最多为512字节,如果存储在MBR中,则只能最大为446字节。stage1中保存了stage1.5的地址,并负责加载stage1.5的前512字节。之所以stage1只能加载512字节,是为了遵循MBR的规则。

进入stage1.5,由于只加载了前512字节,所以stage1.5首先要负责把剩余部分代码,由自己加载到内存中。对于stage1.5来说,它可以识别和支持文件系统。可以查看/boot/grub目录下,有多个后缀为stage1.5文件,其前缀即为支持的文件系统,也就是说要支持一个文件系统,就有一个对应的stage1.5文件。至于加载哪个文件,已经硬编码在stage1中。这个文件系统为stage2所在的文件系统。stage2文件是真正保存在文件系统中的。这样通过对应的stage1.5文件,就可以正确加载stage2文件。为什么会有stage1.5这个阶段呢?主要是当stage2不连续或者需要在stage2前,对文件系统做些特殊处理。如果没有这样的需求,完全可以避免stage1.5。

stage2文件为最主要的加载代码,这时由于已经stage1.5已经支持文件系统了,所以stage2可以比较大。stage2来实现GRUB的各种功能,这里就不列举了,感兴趣的同学可以自己查看GRUB的手册。stage2首先需要找到GRUB的配置文件,来决定如何加载操作系统。对于GRUB的配置与本文的主题联系并不紧密,我个人也对其兴趣不大。

GRUB不仅要复杂加载kernel,还要负责加载Initial Ram Disk,又被成为initrd。其目的主要是为了保证一个小体积的内核。initrd为一个简单的文件系统,它包含了一些内核必要的文件和模块。这样,首先将initrd挂载为一个根系统,然后kernel利用这个基本的系统,来检测环境,加载更多的必要的模块。在完成所有的加载后,这时kernel已经完全准备就绪。那么initrd对于kernel来说,已经不需要了。这时,kernel会将initrd从根/上卸载,并挂载上真正的根系统,并执行正常的启动程序。

Linux内核加载全流程的更多相关文章

  1. 修改linux内核加载顺序

    修改内核启动顺序:1.查看当前系统所有的内核# awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/gr ...

  2. 内核加载与linux的grub

    计算机系统的启动是一个复杂的过程,启动过程大致可以分为以下几个阶段: +------计算机系统启动流程----------------------------- ------------------- ...

  3. bootrom/spl/uboot/linux逐级加载是如何实现的?

    关键词:bootrom.spl.uboot.linux.mksheader.sb_header.mkimage.image_header_t等等. 首先看一个典型的bootrom->spl-&g ...

  4. bootm命令中地址参数,内核加载地址以及内核入口地址

    bootm命令只能用来引导经过mkimage构建了镜像头的内核镜像文件以及根文件镜像,对于没有用mkimage对内核进行处理的话,那直接把内核下载到连接脚本中指定的加载地址0x30008000再运行就 ...

  5. Android引入高速缓存的异步加载全分辨率

    Android引进高速缓存的异步加载全分辨率 为什么要缓存 通过图像缩放,我们这样做是对的异步加载优化的大图,但现在的App这不仅是一款高清大图.图.动不动就是图文混排.以图代文,假设这些图片都载入到 ...

  6. Linux内核网络报文简单流程

    转:http://blog.csdn.net/adamska0104/article/details/45397177 Linux内核网络报文简单流程2014-08-12 10:05:09 分类: L ...

  7. Linux驱动之内核加载模块过程分析

    Linux内核支持动态的加载模块运行:比如insmod first_drv.ko,这样就可以将模块加载到内核所在空间供应用程序调用.现在简单描述下insmod first_drv.ko的过程 1.in ...

  8. Linux开机加载过程

    2015-01-06 10:29:13   目录 1 开机加载简介 2 常规加载流程 2.1 加载BIOS 2.2 读取MBR 2.3 boot loader 2.4 加载内核 2.5 init依据i ...

  9. Linux0.11内核--加载可执行二进制文件之3.exec

    最后剩下最核心的函数do_execve了,由于这里为了简单起见我不分析shell命令的情况, /* * 'do_execve()'函数执行一个新程序. */ //// execve()系统中断调用函数 ...

随机推荐

  1. 通过gdb跟踪Linux内核装载和启动可执行程序过程

    作者:吴乐 山东师范大学 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验目的:通过对一个简单的可执 ...

  2. 通过简单的Linux内核启动程序代码窥探操作系统的启动原理

    作者:吴乐  山东师范大学 <Linux内核分析> 孟宁 MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.程序设计与分析 ...

  3. C语言基础知识--位运算

    1.原码,反码,补码: (1)在n位的机器数中,最高位为符号位,该位为零表示为正,为一表示为负:其余n-1位为数值位,各位的值可为零或一.当真值为正时,原码.反码.补码数值位 完全相同:当真值为负时, ...

  4. Min Edit Distance

    Min Edit Distance ----两字符串之间的最小距离 PPT原稿参见Stanford:http://www.stanford.edu/class/cs124/lec/med.pdf Ti ...

  5. Camera图片特效处理综述(Bitmap的Pixels处理、Canvas/paint的drawBitmap处理、旋转图片、裁截图片、播放幻灯片浏览图片<线程固定时间显示一张>)

    一种是直接对Bitmap的像素进行操作,如:叠加.边框.怀旧.(高斯)模糊.锐化(拉普拉斯变换). Bitmap.getPixels(srcPixels, 0, width, 0, 0, width, ...

  6. svn跳过某个目录

    svn up --set-depth exclude dir2 http://stackoverflow.com/questions/1439176/svn-can-you-remove-direct ...

  7. 取消本地SVN文件夹与服务器关联

    问题:之前建了一个SVN代码库,同步了代码上去,但中途发现建库时的规则搞错了,就把服务器上的库给删了重建,然后改变本地代码的svn服务器关联地址,但使用Relocate一直报错. 错误有两种情况:1. ...

  8. [cocos2d-x]File文件的IO读写处理

    转载:http://blog.csdn.net/chiuan/article/details/8618411 为了保存自定义数据文件,需要保存文件和读取文件,也就是File的IO处理: 针对cocos ...

  9. Web Service学习之二:Web Service(for JAVA)的几种框架

    在讲Web Service开发服务时,需要介绍一个目前开发Web Service的几个框架,分别为Axis,axis2,Xfire,CXF以及JWS(也就是前面所述的JAX-WS,这是Java6发布所 ...

  10. POJ Wormholes (SPFA)

    http://poj.org/problem?id=3259 Description While exploring his many farms, Farmer John has discovere ...