博文无法面面俱到,本人能力有限,描述过程可能没有涉及到所有内容,有什么错误的地方大家一起讨论.博文风格觉得不好的地方也可以给我留言,我好改正.

目录:
       一.深入理解开机启动流程
       二.启动流程值BIOS详解
       三.启动流程之grub详解
       四.启动流程之initid详解
       五.grub配置文件详解
       六.grub安装和initrd制作
       七.配置grub文件
       八.自动化脚本
       九.相关扩展阅读


一.深入理解开机启动流程
   说到开机启动流程相关博文是满天飞,可是很少有博文能够讲解的很深入,大多都是泛泛而谈,很多问题都没有详尽的进行解答.例如 系统开机时怎么加载BIOS的程序的呢?,BIOS怎么可以访问硬盘而加载MBR中的bootloader呢,不需要相关驱动吗?等等一系列问题
今天我在这里谈不上详解吧,我会尽我的能力最大的解释清楚一些启动过程中的问题.

上面的是一个简单的介绍,下面针对每一个部分进行详尽解释
   1.电源加电的一刻,CPU通过自举电路,(RESET)重置信号重置了自己的寄存器的值使其值正好指向了ROM中BIOS程序的地址将其加载到内存中

   2.BIOS是一段代码其功能主要有两个:一个是完成加电自检(POST),另外一个就是完成基本的输入输出服务

   3.BIOS完成POST后首先会根据COMS(需要电池保存其配置信息)中的设置寻找第一个处于活动状态的可启动的设备(软盘,硬盘,U盘,光盘等)

   4.BIOS找到指定设备后会利用BIOS中提供的INT13H的2号功能来读出改设备的MBR中的内容(一个扇区512字节),MBR中存放的是bootloader引导管理器

   5.linux下主流的bootloader是lilo和grub,目前linux系统主要使用grub或grub2.  

   6.grub被加载到内存中后就会根据相关配置文件寻址内核镜像,由于内核镜像一般没有附带一些类型的硬盘驱动,所以先要加载initrd

   7.initrd中附带了硬盘的相关驱动,在initrd中加载相关驱动并最终切换根文件系统,执行系统的第一个进程init.


二.启动流程值BIOS详解
1.BIOS是什么?
   BIOS无非就是一段卸载EEPROM中的一段程序而已.
586以后的主板上BIOS ROM的芯片基本上都采用了EEPROM(Electrically Erasable Programmable ROM)电可擦除可编程ROM.
通过跳线开关和系统配带的驱动程序盘,可以对EEPROM进行重写,方便地实现BIOS升级。

2.BIOS具有什么功能?
   BIOS用于计算机开机时执行系统各部分的的自检,并启动引导程序或装载在内存的操作系统。此外,BIOS还向操作系统提供一些系统参数。

3.BIOS和COMS的区别和联系
联系: CMOS是计算机上另一个重要的存储器。之所以提到它,是因为BIOS程序的设置结果就保存在CMOS中。而且,在BIOS程序引导计算机启动后,计算机需要载入CMOS中的用户信息和常规设置后才能正常使用。
区别: BIOS与CMOS都是存储器。二者的区别是BIOS为只读存储器(ROM或EPROM),而CMOS为随机存储器(RAM);BIOS中存储的是程序,而CMOS中存储的是普通信息。



三.启动流程之grub详解
 1.grub主要有stage1,stage1.5,stage2三个阶段组成,BIOS加载MBR中的bootloader,其实质就是加载stage1
 2.stage1开始加载stage1.5,stage1.5阶段主要是为了加载一些文件系统的驱动,我们可以看下/boot/grub目录下的文件来验证

[root@litte grub]# pwd
/boot/grub
[root@litte grub]# ls
device.map     fat_stage1_5  grub.conf         jfs_stage1_5  minix_stage1_5     splash.xpm.gz  stage2         vstafs_stage1_5
e2fs_stage1_5  ffs_stage1_5  iso9660_stage1_5  menu.lst      reiserfs_stage1_5  stage1         ufs2_stage1_5  xfs_stage1_5

我们会发现大量以文件名中含有*stage1_5命名的文件,这其实即使就是各个不同文件系统的驱动
3.stage1.5阶段以文件系统方式加载了stage2阶段,这个阶段会读取配置文件生成可选择的菜单供用户选择要加载的内核,并提供菜单的背景

   4.stage2通过用户的选择加载相应的initrd文件,到此grub生命周期结束,控制权转交给initrd文件


四.启动流程之initid详解

1.initrd是什么?
   initrd是在系统引导过程中挂载的一个临时根文件系统,用来支持两阶段的引导过程。initrd 文件中包含了各种可执行程序和驱动程序,
   它们可以用来挂载实际的根文件系统,然后再将这个 initrd RAM 磁盘卸载,并释放内存。在很多嵌入式 Linux 系统中,initrd 就是最终的根文件系统。

2.为什么要使用initrd?
   最主要的目的是加载根文件系统存储介质的驱动模块。我们知道根文件系统可以存储在包括IDE、SCSI、USB在内的多种介质上,如果将这些设备的驱动都编译进内核,可以想象内核会多么庞大、臃肿。

3.initrd的加载流程?
1. boot loader 把内核以及 initrd 文件加载到内存的特定位置。
2. 将initrd的内容释放到rootfs中。

   3. 执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全交给/init文件处理。
4.  init文件的功能(init文件 其实是一个nash脚本,和linux系统的第一个进程init不一样)

1.挂载proc,sys目的之为了获取内核输出的信息进行硬件探测
2.挂载/dev/pts,/dev/shm,/dev/mapper
3.通过mknod命令创建设备文件(linux系统是通过udev进行设备文件的自动创建的)
4.通过insmod命令加载相关硬盘驱动和文件系统驱动
5.挂载根文件系统
6.切换真正的root,并执行init程序



五.grub配置文件详解

1.获取硬盘上的grub
dd if=/dev/sda of=/root/mbr.bak bs=512 count=1

2.grub配置文件详解
grub.conf



default=0
 #设置默认加载的内核 0代表第一个title处指定的内核镜像
timeout=5
 #菜单选择超时时间,5秒后不选择的话就会启动默认项
splashp_w_picpath=(hd0,0)/grub/splash.xpm.gz
#指定加载的grub菜单的背景图片
hiddenmenu    #隐藏启动菜单
title CentOS (2.6.18-308.el5) #菜单显示信息
        root (hd0,0)         
#指定内核的位置 任何类型的硬盘grub都是hd#形式,
#第一块硬盘就是0,第一个分区就是0
        kernel /vmlinuz-2.6.18-308.el5 ro root=LABEL=/
#指定内核镜像文件
        initrd /initrd-2.6.18-308.el5.img
#指定initrd镜像文件


其它额外参数介绍:
password
   指定用户在能够解锁菜单、编辑一个配置行或输入 GRUB 命令前必须输入的密码。这个密码可能是明文格式。GRUB 还允许将密码存储为一个 MD5 摘要,我们的示例就是这样做的。这样更安全一些,大多数管理员都会设置一个密码。如果不设置密码,用户就能够完全访问 GRUB 命令行。

boot
   一个可选参数,指示 GRUB 启动选择的操作系统。当一个选项所有命令全部执行完时,这将是一个默认操作。

lock
   本示例中不使用。没有输入密码之前不会启动指定项。如果使用这个命令,那么还应该在初始选项中指定一个密码;
   否则,用户可以编辑您的锁定选项并启动系统,或者添加 “single” 到其中的一项。如果您愿意的话,还可以为个别条目指定一个不同的密码。

rootnoverify
   类似于 root,除非 GRUB 不尝试挂载文件系统或验证其参数。这通常用于 GRUB 不支持的文件系统,比如 NIFS。
   如果您想要 GRUB 加载硬盘驱动器上的主引导记录,也可以使用这个命令,例如,访问不同的配置文件或者重新加载您之前的启动加载程序。

chainloader
   指定将作为阶段 1 文件加载的另一个文件。值 “+1” 等同于 0+1,表示加载从扇区 0 开始的一个扇区,即从 root 或 rootnoverify 指定的设备加载第一个扇区。


六.grub安装和initrd制作
下面我将一步一步操作完成一个小linux系统
1.首先给虚拟机中的linux系统添加一块硬盘.(添加的硬盘选择保存硬盘的形式为单个文件)
 2.分区,创建一个用于挂载到boot上的分区和一个用于挂载到根目录下的分区
3.给两个文件系统分别创建文件系统
4.创建一个/mnt/boot(必须包含boot这个目录,grub安装的时候会找指定目录下的boot目录)和/mnt/sysroot
下面是我的分区信息:

Disk /dev/sdb: 5368 MB, 5368709120 bytes
255 heads, 63 sectors/track, 652 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1          13      104391   83  Linux
/dev/sdb2              14         136      987997+  83  Linux


下面是我的挂载信息:

/dev/sdb1 on /mnt/boot type ext3 (rw)
/dev/sdb2 on /mnt/sysroot type ext3 (rw)

5.安装grub

[root@wwww ~]# grub-install --root-directory=/mnt/ /dev/sdb
Probing devices to guess BIOS drives. This may take a long time.
Installation finished. No error reported.
This is the contents of the device map /mnt//boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install'.
(fd0)    /dev/fd0
(hd0)    /dev/sda
(hd1)    /dev/sdb


6.利用宿主机系统自动的initrd文件修改(后期会利用busybox来创建)
1.解压宿主机上的initrd文件

[root@wwww ~]# cp /boot/initrd-2.6.18-308.el5.img /root/initrd.img
[root@wwww ~]# file /root/initrd.img
/root/initrd.img: gzip compressed data, from Unix, last modified: Fri Nov  8 17:15:18 2013, max compression
[root@wwww ~]# mv /root/initrd.img /root/initrd.img.gz
[root@wwww ~]# gzip -d /root/initrd.img.gz
[root@wwww ~]# file initrd.img
initrd.img: ASCII cpio archive (SVR4 with no CRC)
[root@wwww ~]# mkdir tmpdir
[root@wwww ~]# cd tmpdir/
[root@wwww tmpdir]# cpio -id  < /root/initrd.img
14113 blocks
[root@wwww tmpdir]# ls
bin  dev  etc  init  lib  proc  sbin  sys  sysroot

2.修改initrd文件中的init脚本
下面是该文件的部分内容    

#!/bin/nash  #该文件是个nash脚本
mount -t proc /proc /proc
setquiet
echo Mounting proc filesystem
echo Mounting sysfs filesystem
mount -t sysfs /sys /sys
echo Creating /dev
mount -o mode=0755 -t tmpfs /dev /dev
mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
mkdir /dev/shm
mkdir /dev/mapper
echo Creating initial device nodes
mknod /dev/null c 1 3
mknod /dev/zero c 1 5
mknod /dev/urandom c 1 9
mknod /dev/systty c 4 0
mknod /dev/tty c 5 0
mknod /dev/console c 5 1
mknod /dev/ptmx c 5 2
mknod /dev/rtc c 10 135
mknod /dev/tty0 c 4 0
mknod /dev/tty1 c 4 1
mknod /dev/tty2 c 4 2
mknod /dev/tty3 c 4 3
mknod /dev/tty4 c 4 4
mknod /dev/tty5 c 4 5
echo Setting up hotplug.
hotplug
echo Creating block device nodes.
mkblkdevs
echo "Loading ehci-hcd.ko module"
insmod /lib/ehci-hcd.ko
echo "Loading ohci-hcd.ko module"
insmod /lib/ohci-hcd.ko
echo "Loading uhci-hcd.ko module"
insmod /lib/uhci-hcd.ko
mount -t usbfs /proc/bus/usb /proc/bus/usb
echo "Loading jbd.ko module"
insmod /lib/jbd.ko
echo "Loading ext3.ko module"
insmod /lib/ext3.ko
echo "Loading scsi_mod.ko module"
insmod /lib/scsi_mod.ko
echo "Loading sd_mod.ko module"
insmod /lib/sd_mod.ko
echo "Loading scsi_transport_spi.ko module"
insmod /lib/scsi_transport_spi.ko
echo "Loading mptbase.ko module"
insmod /lib/mptbase.ko
echo "Loading mptscsih.ko module"
insmod /lib/mptscsih.ko
echo "Loading mptspi.ko module"
echo Setting up hotplug.
hotplug
echo Creating block device nodes.
mkblkdevs
#下面的这些加载的模块可以适当去除,我这里只保存了我需要的驱动,scsi驱动和ext3驱动
#echo "Loading ehci-hcd.ko module"
#insmod /lib/ehci-hcd.ko
#echo "Loading ohci-hcd.ko module"
#insmod /lib/ohci-hcd.ko
#echo "Loading uhci-hcd.ko module"
#insmod /lib/uhci-hcd.ko
mount -t usbfs /proc/bus/usb /proc/bus/usb
echo "Loading jbd.ko module"
insmod /lib/jbd.ko
echo "Loading ext3.ko module"
insmod /lib/ext3.ko
echo "Loading scsi_mod.ko module"
insmod /lib/scsi_mod.ko
echo "Loading sd_mod.ko module"
insmod /lib/sd_mod.ko
echo "Loading scsi_transport_spi.ko module"
insmod /lib/scsi_transport_spi.ko
echo "Loading mptbase.ko module"
#insmod /lib/mptbase.ko
#echo "Loading mptscsih.ko module"
#insmod /lib/mptscsih.ko
#echo "Loading mptspi.ko module"
#insmod /lib/dm-raid45.ko
echo Waiting for driver initialization.
stabilized --hash --interval 1000 /proc/scsi/scsi
mkblkdevs
#echo Scanning and configuring dmraid supported devices
#resume LABEL=SWAP-sda3                                      
#我没有交换分区所以这里取消了swap分区的设置
echo Creating root device.
mkrootdev -t ext3 -o defaults,ro /dev/sda2
#主要修改的地方,确定根目录所在分区和类型,这里因为宿主机系统根目录所在分区是/dev/sda2,
#我们刚才创建的根目录是挂载到/dev/sdb2上,但是这块硬盘当放到其他主机上当只有一块硬盘的时
#候这块硬盘是被识别成/dev/sda2的,所以这里要看具体情况来修改,我这里不做修改
#另外还需要注意你的硬盘类型,如果选的是SATA类型的这里就要写成/dev/hda2了,我选的是scsi类型
echo Mounting root filesystem.
mount /sysroot
echo Setting up other filesystems.
setuproot
echo Switching to new root and running init.
switchroot

 3.封装initrd文件

[root@wwww tmpdir]# find .|cpio -H newc -o |gzip -9 > /mnt/boot/initrd.gz
14113 blocks

4.复制内核镜像文件

[root@wwww tmpdir]# cp /boot/vmlinuz-2.6.18-308.el5 /mnt/boot/vmlinux


七.配置grub文件

[root@wwww sysroot]# cd /mnt/boot/grub
[root@wwww grub]# vim grub.conf
default=0
timeout=5
title My linux
        root (hd0,0)
        kernel  /vmlinux
        initrd  /initrd.gz


   到此为止一个简单的linux制作完成,但是还需要系统初始化进行一些设置,不然是无法进入系统的,此时我们在虚拟机中重新创建一个虚拟机加载添加的那块硬盘,设置从这个硬盘启动我们就可以看到grub引导菜单
下篇博文将会介绍怎么进行系统初始化完成进入linux系统的功能



八.自动化脚本
脚本临时写的有点垃圾,但是测试通过了,后期会完善脚本,此脚本基本就是命令的堆砌,很多地方没有进行判断.


#!/bin/bash
#author:Jeff_linux
#time:2014.1.18
#
# "please add a disk"
disk="/dev/sdb"
# "clear partition table"
dd if=/dev/zero of=$disk bs=512 count=1
# "start partition"
cat <<EOF | fdisk $disk
n
p
1
+100M
n
p
2
+1G
w
q
EOF
# "The kernel on the partition table"
partprobe $disk
# "creat filesystem"
mke2fs -j ${disk}1
mke2fs -j ${disk}2
sleep 3
# "create mount point"
mkdir /mnt/sysroot
mkdir /mnt/boot
mount -t ext3 ${disk}1 /mnt/boot
mount -t ext3 ${disk}2 /mnt/sysroot
# "create initrd file"
cp /boot/initrd-`uname -r`.img /tmp/initrd.gz
gzip -d /tmp/initrd.gz
cd /tmp
mkdir tmpdir
cd tmpdir
cpio -id </tmp/initrd
cat >init <<EOF
#!/bin/nash
mount -t proc /proc /proc
setquiet
echo Mounting proc filesystem
echo Mounting sysfs filesystem
mount -t sysfs /sys /sys
echo Creating /dev
mount -o mode=0755 -t tmpfs /dev /dev
mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
mkdir /dev/shm
mkdir /dev/mapper
echo Creating initial device nodes
mknod /dev/null c 1 3
mknod /dev/zero c 1 5
mknod /dev/urandom c 1 9
mknod /dev/systty c 4 0
mknod /dev/tty c 5 0
mknod /dev/console c 5 1
mknod /dev/ptmx c 5 2
mknod /dev/rtc c 10 135
mknod /dev/tty0 c 4 0
mknod /dev/tty1 c 4 1
mknod /dev/ttyS0 c 4 64
mknod /dev/ttyS1 c 4 65
echo Setting up hotplug.
hotplug
echo Creating block device nodes.
mkblkdevs
echo "Loading jbd.ko module"
insmod /lib/jbd.ko
echo "Loading ext3.ko module"
insmod /lib/ext3.ko
echo "Loading scsi_mod.ko module"
insmod /lib/scsi_mod.ko
echo "Loading sd_mod.ko module"
insmod /lib/sd_mod.ko
echo "Loading scsi_transport_spi.ko module"
insmod /lib/scsi_transport_spi.ko
echo "Loading mptbase.ko module"
insmod /lib/mptbase.ko
echo "Loading mptscsih.ko module"
insmod /lib/mptscsih.ko
echo "Loading mptspi.ko module"
insmod /lib/mptspi.ko
echo "Loading libata.ko module"
insmod /lib/libata.ko
echo Waiting for driver initialization.
stabilized --hash --interval 1000 /proc/scsi/scsi
mkblkdevs
echo Creating root device.
mkrootdev -t ext3 -o defaults,ro /dev/sda2
echo Mounting root filesystem.
mount /sysroot
echo Setting up other filesystems.
setuproot
echo Switching to new root and running init.
switchroot
EOF
chmod 700 init
# "Initrd file package"
find .|cpio -H newc -o|gzip -9 > /mnt/boot/initrd.gz
#copy kernel file
cp /boot/vmlinuz-`uname -r` /mnt/boot/vmlinux
#install grub
grub-install --root-directory=/mnt $disk
#The configuration of grub
cd /mnt/boot/grub
cat > grub.conf <<EOF
default=0
timeout=5
title My linux
        root (hd0,0)
        kernel  /vmlinux
        initrd  /initrd.gz
EOF
echo "setup sucess"



九.相关扩展阅读

1.Linux 引导过程内幕
http://www.ibm.com/developerworks/cn/linux/l-linuxboot/
2.Linux 初始 RAM 磁盘(initrd)概述
http://www.ibm.com/developerworks/cn/linux/l-initrd.html
3.学习 Linux,101: 引导管理器
http://www.ibm.com/developerworks/cn/linux/l-lpic1-v3-102-2/