在这篇随笔里面将对Linux系统的启动进行一个详细的解释!我的实验机器是CentOS6.4,当然对于现有的Linux发行版本,其系统的启动基本上都是一样的!
首先我们来看下Linux系统启动的几个步骤:
对于Linux系统来说,系统的整个启动过程就是分为这6个部分。下面将对每一个部分的启动时所完成的功能进行详细解释。
一、BIOS
对于BIOS我想大家应该都不陌生,只要是PC机,当电脑启动时第一个运行的就是BIOS。BIOS(Basic Input Output System)我们称之为基本输入输出系统,一般都是保存在主板上的BIOS芯片中。
计算机启动时第一个运行的就是BIOS,BIOS主要是负责对硬件进行检查,比如检查接在主板上的各种PCI硬件设备,当电脑的硬件检测不通过时,电脑就会发出滴滴的声音,这时我们就要对硬件进行检查了。如果BIOS对硬件检测通过的话,它就继续进行下一个操作,也就是查找可启动设备。
对于可启动设备在BIOS设置中进行定义,常见的可启动设备包括USB、CDROM、HD。
二、MBR
MBR在之前的硬盘分区时有讲过其功能,MBR(Master Boot Recorder),我们称之为主引导记录。BIOS是怎样寻找可启动设备的呢?我们知道在分区时,硬盘的第一块扇区512个字节就是存放的MBR,如果该设备是可启动设备,那么该扇区的最后两个字节肯定是55/AA,所以此时在寻找可启动设备时,如果发现该设备的最后两个字节是这个,那么该设备就是可启动设备。
BIOS在找到可启动设备以后就会执行其引导代码,因为MBR占据了第一块扇区的512字节,分区表占用了 16*4 =64字节,再加上最后两个标志字节,所以MBR的引导代码就是MBR的前446个字节,当然这446个字节太小了,并不能完成整个操作系统的引导程序,所以这446个字节里面可能存放的就是启动引导程序的一些代码。
三、GRUB
GRUB是GRand Unified Bootloader的缩写,它是一个多重操作系统启动管理器。
GRUB是现在Linux使用的主流的引导程序,当然现在的GRUB不仅仅是能引导Linux系统,对于Winodows、Mac OS、BSD等几乎所有系统它都能引导。
GRUB的一些相关配置文件都是保存在了 /boot/grub 这个目录下。我们可以进去看下其里面的内容
[root@xiaoluo ~]# cd /boot/grub/
[root@xiaoluo grub]# ls -l
total 280
-rw-r--r--. 1 root root 63 May 14 01:30 device.map
-rw-r--r--. 1 root root 13380 May 14 01:30 e2fs_stage1_5
-rw-r--r--. 1 root root 12620 May 14 01:30 fat_stage1_5
-rw-r--r--. 1 root root 11748 May 14 01:30 ffs_stage1_5
-rw-------. 1 root root 796 May 14 01:30 grub.conf
-rw-r--r--. 1 root root 11756 May 14 01:30 iso9660_stage1_5
-rw-r--r--. 1 root root 13268 May 14 01:30 jfs_stage1_5
lrwxrwxrwx. 1 root root 11 May 14 01:30 menu.lst -> ./grub.conf
-rw-r--r--. 1 root root 11956 May 14 01:30 minix_stage1_5
-rw-r--r--. 1 root root 14412 May 14 01:30 reiserfs_stage1_5
-rw-r--r--. 1 root root 1341 Nov 15 2010 splash.xpm.gz
-rw-r--r--. 1 root root 512 May 14 01:30 stage1
-rw-r--r--. 1 root root 125992 May 14 01:30 stage2
-rw-r--r--. 1 root root 12024 May 14 01:30 ufs2_stage1_5
-rw-r--r--. 1 root root 11364 May 14 01:30 vstafs_stage1_5
-rw-r--r--. 1 root root 13964 May 14 01:30 xfs_stage1_5
我们看到在grub目录下存放了许多的文件,我们大致先了解一下这些文件所代表的含义。
对于stage1文件,我们可以看到其大小为512个字节,这个文件其实就是上面所说的MBR的一个备份,如果之前的MBR出问题了,我们可以使用这个stage1来恢复过来。对于另外一些例如e2fs_stage1_5、fat_stage1_5等这些文件,这些文件是在stage1执行完才执行的。这些文件前面的单词都是一些文件系统的名字,那么为什么要加载这么多的文件系统呢?因为当我们GRUB引导程序运行完就要去加载文件系统中的操作系统内核了(kernel),而对于不同的操作系统可能文件系统不相同,所以这里在执行完stage1以后加载这么多的文件系统就是为了去找到操作系统的内核以及驱动信息。在这些执行完以后就是执行stage2这个文件了,这个文件我们看到它有 125992 字节,整个操作系统的引导程序代码就是在这里了。
对于GRUB,其主配置文件是存放在grub.conf这个文件里面的,我们可以看下这个文件里面的内容:
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You do not have a /boot partition. This means that
# all kernel and initrd paths are relative to /, eg.
# root (hd0,1)
# kernel /boot/vmlinuz-version ro root=/dev/sda2
# initrd /boot/initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,1)/boot/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.32-358.el6.x86_64)
root (hd0,1)
kernel /boot/vmlinuz-2.6.32-358.el6.x86_64 ro root=UUID=6e24ec7a-2d19-466e-bacc-92750b1f4bef rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /boot/initramfs-2.6.32-358.el6.x86_64.img
我们对其每行配置文件代表的信息来分析一下。
default=0代表的是选择第几个配置,下面的每一个titile 代表一个操作系统的配置信息,如果有多个操作系统信息,则下面就会有多个titile,这里default=0,表示默认使用第一个操作系统的配置,也就是使用第一个title。
timeout=5,表示刚进入系统时默认等待的时间,这个我们可以修改,如果将其修改成0,则系统直接进入引导。
splashimage=(hd0,1)/boot/grub/splash.xpm.gz表示的是倒计时界面下,页面显示的背景图片
hiddenmenu表示隐藏菜单
title表示每一个操作系统的配置,后面跟的CentOS (2.6.32-358.el6.x86_64)就是操作系统的名字,这个可以自己随便取名
下面的
①root (hd0,1)
表示操作系统的 /boot 分区所在硬盘的分区,hd0,1表示第一块硬盘的第二个分区,我们当前操作系统的/boot分区就是在这个分区下。
②kernel /boot/vmlinuz-2.6.32-358.el6.x86_64 ro root=UUID=6e24ec7a-2d19-466e-bacc-92750b1f4bef rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
这个表示的是操作系统的内核存放位置,当前的CentOS操作系统的内核就是存放着 /boot 目录下的vmlinuz-2.6.32-358.el6.x86_64, 后面跟的是内核的参数,ro表示只读的,每一个参数都用空格隔开
③initrd /boot/initramfs-2.6.32-358.el6.x86_64.img
Linux为什么启动的速度那么快,是因为其操作系统的内核非常的精简,为了让Linux的内核保持精简,我们就将其不常用的驱动、功能编译为模块,在需要的时候对其进行动态加载。所以这个initrd就是存放的是我们的那些不常用的驱动、功能所编译成的模块。之前的Linux版本里面使用的是initrd文件,initramfs是initrd的一个替代优化版本,比initrd更加节省空间、更加灵活。所以现在的Linux版本都是用的是initramfs。
我们如果有多个操作系统的配置信息的话,就要在下面再定义一个title,然后按照上面的格式,定义好/boot分区的目录以及内核的目录等
四、Kernel
MBR引导代码就是为了启动GRUB去加载操作系统的内核,Linux系统的内核都是存放在/boot目录下
[root@xiaoluo boot]# ls -l vmlinuz-2.6.32-358.el6.x86_64
-rwxr-xr-x. 1 root root 4043888 Feb 22 08:56 vmlinuz-2.6.32-358.el6.x86_64
操作系统在加载内核时的时候通常还会去加载内核模块打包文件:/boot/initramfs-2.6.32-358.el6.x86_64.img
我们在系统启动完后通过 dmesg 命令可以查看本次启动时操作系统的内核输出信息,这样可以操作系统内核出现问题时对其进行错误排查
[root@xiaoluo boot]# dmesg
Initializing cgroup subsys cpuset
Initializing cgroup subsys cpu
Linux version 2.6.32-358.el6.x86_64 (mockbuild@c6b8.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) ) #1 SMP Fri Feb 22 00:31:26 UTC 2013
Command line: ro root=UUID=6e24ec7a-2d19-466e-bacc-92750b1f4bef rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
KERNEL supported cpus:
Intel GenuineIntel
AMD AuthenticAMD
Centaur CentaurHauls
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
BIOS-e820: 000000000009fc00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000f0000 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 00000000207f0000 (usable)
BIOS-e820: 00000000207f0000 - 0000000020800000 (ACPI data)
BIOS-e820: 00000000fffc0000 - 0000000100000000 (reserved)
DMI 2.5 present.
SMBIOS version 2.5 @ 0xFFF60
DMI: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
e820 update range: 0000000000000000 - 0000000000001000 (usable) ==> (reserved)
e820 remove range: 00000000000a0000 - 0000000000100000 (usable)
last_pfn = 0x207f0 max_arch_pfn = 0x400000000
MTRR default type: uncachable
MTRR variable ranges disabled:
x86 PAT enabled: cpu 0, old 0x7040600070406, new 0x7010600070106
CPU MTRRs all blank - virtualized system.
***************************省略N个字***********************************************************
我们看到其输出了非常多的信息,都是操作系统启动时,内核的输出信息。当然我们可以在 /var/log 目录下发现也有一个 dmesg 文件,这个文件存放的内容和通过 dmesg 命令输出的内容是一模一样的
[root@xiaoluo ~]# ls -l /var/log/dmesg
-rw-r--r--. 1 root root 21190 May 19 13:06 /var/log/dmesg
五、init
在操作系统加载完内核以后,这时就会运行操作系统上的第一个进程 init,我们可以通过 ps -aux | more 命令来看一下
[root@xiaoluo ~]# ps -aux | more
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.2 19348 1464 ? Ss 13:05 0:01 /sbin/init
我们看到操作系统运行的第一个进程就是 init 进程,这个进程在启动以后就会一直运行,直到系统退出关机。
init进程会调用 /etc/rc.d/rc.sysinit 这个脚本对系统进行初始化,挂载文件系统,并且根据运行基本启动相应的服务。
Linux系统的运行级别:
-0 关机 -1 单用户模式 -2 不带网络的多用户模式 -3 多用户模式 -4 未使用 -5 X11图形化模式 -6 重新启动
我们通常将其设置成3或者5,运行级别3和5的唯一不同,就是是否启动时拥有图形界面。在生产环境下我们通常将其设置成3,直接进入到命令行终端模式
我们可以通过修改 /etc/inittab 这个文件来修改系统默认的运行级别:
[root@xiaoluo ~]# cat /etc/inittab
# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# System initialization is started by /etc/init/rcS.conf
#
# Individual runlevels are started by /etc/init/rc.conf
#
# Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
#
# Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
# with configuration in /etc/sysconfig/init.
#
# For information on how to write upstart event handlers, or how
# upstart works, see init(5), init(8), and initctl(8).
#
# Default runlevel. The runlevels used are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
id:5:initdefault:
我们看到当前的运行基本默认是5,也就是拥有图形界面。
其实在/etc目录下还有一个init目录,里面存放的是init的其它一些配置文件
[root@xiaoluo ~]# cd /etc/init
[root@xiaoluo init]# ll
total 68
-rw-r--r--. 1 root root 260 Jan 9 19:13 control-alt-delete.conf
-rw-r--r--. 1 root root 130 Jun 22 2012 init-system-dbus.conf
-rw-r--r--. 1 root root 316 Jan 9 19:13 kexec-disable.conf
-rw-r--r--. 1 root root 409 Jan 9 19:13 plymouth-shutdown.conf
-rw-r--r--. 1 root root 217 Jan 9 19:13 prefdm.conf
-rw-r--r--. 1 root root 358 Jan 9 19:13 quit-plymouth.conf
-rw-r--r--. 1 root root 281 Jan 9 19:13 rc.conf
-rw-r--r--. 1 root root 909 Jan 9 19:13 rcS.conf
-rw-r--r--. 1 root root 283 Jan 9 19:13 rcS-emergency.conf
-rw-r--r--. 1 root root 580 Jan 9 19:13 rcS-sulogin.conf
-rw-r--r--. 1 root root 2915 Aug 23 2010 readahead-collector.conf
-rw-r--r--. 1 root root 1559 Aug 23 2010 readahead.conf
-rw-r--r--. 1 root root 726 Aug 23 2010 readahead-disable-services.conf
-rw-r--r--. 1 root root 1162 Jan 9 19:13 serial.conf
-rw-r--r--. 1 root root 643 Jan 9 19:13 splash-manager.conf
-rw-r--r--. 1 root root 329 Jan 9 19:13 start-ttys.conf
-rw-r--r--. 1 root root 198 Jan 9 19:13 tty.conf
我们可以看到,这里面有许多的配置文件,我们可以根据自己的需要修改其里面的内容,这样init进程启动时就会去执行里面的功能。
我们通过 runlevel 命令可以查看我们当前的以及上一次的启动级别:
[root@xiaoluo init]# runlevel
N
N表示没有上一个启动级别,5表示当前的启动级别
通过init命令我们可以修改当前的系统运行级别,例如输入 init 3,此时操作系统就会进入到命令行模式
通过statx命令 或者init 5 命令就可以回到运行级别5的模式
每个运行级别启动时的对应启动服务都是保存在了 /etc/rc.d/rc[0123456].d中,例如我们当前的运行级别是5,则操作系统的启动服务就是在 /etc/rc.d/rc5.d这个目录下,里面都是运行级别5所需启动的服务
[root@xiaoluo rc.d]# ls
init.d rc0.d rc2.d rc4.d rc6.d rc.sysinit
rc rc1.d rc3.d rc5.d rc.local
至此,整个Linux操作系统就已经全部的启动起来了。