linux的启动流程详解
linux启动流程
⼀、第⼀阶段:BIOS
上个世纪70年代初,"只读内存"(read-only memory,缩写为ROM)发明,开机程序被刷⼊ROM芯⽚,计算机通电后,第⼀件事就是读取它。
这块芯⽚⾥的程序叫做"基本輸出輸⼊系統"(Basic Input/Output System),简称为BIOS。
1.1 硬件⾃检
BIOS程序⾸先检查,计算机硬件能否满⾜运⾏的基本条件,这叫做"硬件⾃检"(Power-On Self-Test),缩写为POST。
如果硬件出现问题,主板会发出不同含义的蜂鸣,启动中⽌。如果没有问题,屏幕就会显⽰出CPU、内存、硬盘等信息。
1.2 启动顺序
硬件⾃检完成后,BIOS把控制权转交给下⼀阶段的启动程序。
这时,BIOS需要知道,"下⼀阶段的启动程序"具体存放在哪⼀个设备。也就是说,BIOS需要有⼀个外部储存设备的排序,排在前⾯的设备就是优先转交控制权的设备。这种排序叫做"启动顺序"(Boot Sequence)。
打开BIOS的操作界⾯,⾥⾯有⼀项就是"设定启动顺序"。
⼆、第⼆阶段:主引导记录
BIOS按照"启动顺序",把控制权转交给排在第⼀位的储存设备。
这时,计算机读取该设备的第⼀个扇区,也就是读取最前⾯的512个字节。如果这512个字节的最后两个字节是0x55和0xAA,表明这个设备可以⽤于启动;如果不是,表明设备不能⽤于启动,控制权于是被转交给"启动顺序"中的下⼀个设备。
这最前⾯的512个字节,就叫做"主引导记录"(Master boot record,缩写为MBR)。
2.1 主引导记录的结构
"主引导记录"只有512个字节,放不了太多东西。它的主要作⽤是,告诉计算机到硬盘的哪⼀个位置去操作系统。
主引导记录由三个部分组成:
  (1) 第1-446字节:调⽤操作系统的机器码。
  (2) 第447-510字节:分区表(Partition table)。
  (3) 第511-512字节:主引导记录签名(0x55和0xAA)。
其中,第⼆部分"分区表"的作⽤,是将硬盘分成若⼲个区。
2.2 分区表
硬盘分区有很多好处。考虑到每个区可以安装不同的操作系统,"主引导记录"因此必须知道将控制权转交给哪个区。
分区表的长度只有64个字节,⾥⾯⼜分成四项,每项16个字节。所以,⼀个硬盘最多只能分四个⼀级分区,⼜叫做"主分区"。
每个主分区的16个字节,由6个部分组成:
  (1) 第1个字节:如果为0x80,就表⽰该主分区是激活分区,控制权要转交给这个分区。四个主分区⾥⾯只能有⼀个是激活的。
  (2) 第2-4个字节:主分区第⼀个扇区的物理位置(柱⾯、磁头、扇区号等等)。
  (3) 第5个字节:主分区类型。
  (4) 第6-8个字节:主分区最后⼀个扇区的物理位置。
  (5) 第9-12字节:该主分区第⼀个扇区的逻辑地址。
  (6) 第13-16字节:主分区的扇区总数。
最后的四个字节("主分区的扇区总数"),决定了这个主分区的长度。也就是说,⼀个主分区的扇区总数最多不超过2的32次⽅。
如果每个扇区为512个字节,就意味着单个分区最⼤不超过2TB。再考虑到扇区的逻辑地址也是32位,所以单个硬盘可利⽤的空间最⼤也不超过2TB。如果想使⽤更⼤的硬盘,只有2个⽅法:⼀是提⾼每个扇区的字节数,⼆是增加扇区总数。
三、第三阶段:硬盘启动
这时,计算机的控制权就要转交给硬盘的某个分区了,这⾥⼜分成三种情况。
3.1 情况A:卷引导记录
上⼀节提到,四个主分区⾥⾯,只有⼀个是激活的。计算机会读取激活分区的第⼀个扇区,叫做"卷引导记录"(Volume boot record,缩写为VBR)。
"卷引导记录"的主要作⽤是,告诉计算机,操作系统在这个分区⾥的位置。然后,计算机就会加载操作系统了。
3.2 情况B:扩展分区和逻辑分区
linux系统是哪个
随着硬盘越来越⼤,四个主分区已经不够了,需要更多的分区。但是,分区表只有四项,因此规定有且仅有⼀个区可以被定义成"扩展分区"(Extended partition)。
所谓"扩展分区",就是指这个区⾥⾯⼜分成多个区。这种分区⾥⾯的分区,就叫做"逻辑分区"(logical partition)。
计算机先读取扩展分区的第⼀个扇区,叫做"扩展引导记录"(Extended boot record,缩写为EBR)。它⾥⾯也包含⼀张64字节的分区表,但是最多只有两项(也就是两个逻辑分区)。
计算机接着读取第⼆个逻辑分区的第⼀个扇区,再从⾥⾯的分区表中到第三个逻辑分区的位置,以此类推,直到某个逻辑分区的分区表只包含它⾃⾝为⽌(即只有⼀个分区项)。因此,扩展分区可以包含⽆数个逻辑分区。
但是,似乎很少通过这种⽅式启动操作系统。如果操作系统确实安装在扩展分区,⼀般采⽤下⼀种⽅式启动。
3.3 情况C:启动管理器
在这种情况下,计算机读取"主引导记录"前⾯446字节的机器码之后,不再把控制权转交给某⼀个分区,⽽是运⾏事先安装的"启动管理器"(boot loader),由⽤户选择启动哪⼀个操作系统。
Linux环境中,⽬前最流⾏的启动管理器是Grub。
四、第四阶段:操作系统
控制权转交给操作系统后,操作系统的内核⾸先被载⼊内存。
以Linux系统为例,先载⼊/boot⽬录下⾯的kernel。内核加载成功后,第⼀个运⾏的程序是/sbin/init。它根据配置⽂件(Debian系统是/etc/initab)产⽣init进程。这是Linux启动后的第⼀个进程,pid进程编号为1,其他进程都是它的后代。
然后,init线程加载系统的各个模块,⽐如窗⼝程序和⽹络程序,直⾄执⾏/bin/login程序,跳出登录界⾯,等待⽤户输⼊⽤户名和密码。
⾄此,全部启动过程完成。
分割线:扩展知识
半年前,我写了,探讨BIOS和主引导记录的作⽤。
那篇⽂章不涉及操作系统,只与主板的板载程序有关。今天,我想接着往下写,探讨操作系统接管硬件以后发⽣的事情,也就是操作系统的启动流程。
这个部分⽐较有意思。因为在BIOS阶段,计算机的⾏为基本上被写死了,程序员可以做的事情并不多;但是,⼀旦进⼊操作系统,程序员⼏乎可以定制所有⽅⾯。所以,这个部分与程序员的关系更密切。
我主要关⼼的是Linux操作系统,它是⽬前服务器端的主流操作系统。下⾯的内容针对的是发⾏版,因为我对其他发⾏版不够熟悉。
第⼀步、加载内核
操作系统接管硬件以后,⾸先读⼊ /boot ⽬录下的内核⽂件。
以我的电脑为例,/boot ⽬录下⾯⼤概是这样⼀些⽂件:
  $ ls /boot
  config-3.2.0-3-amd64
  config-3.2.0-4-amd64
  grub
  initrd.img-3.2.0-3-amd64
  initrd.img-3.2.0-4-amd64
  System.map-3.2.0-3-amd64
  System.map-3.2.0-4-amd64
  vmlinuz-3.2.0-3-amd64
  vmlinuz-3.2.0-4-amd64
第⼆步、启动初始化进程
内核⽂件加载以后,就开始运⾏第⼀个程序 /sbin/init,它的作⽤是初始化系统环境。
由于init是第⼀个运⾏的程序,它的进程编号(pid)就是1。其他所有进程都从它衍⽣,都是它的⼦进程。
第三步、确定运⾏级别
许多程序需要开机启动。它们在Windows叫做"服务"(service),在Linux就叫做""(daemon)。
init进程的⼀⼤任务,就是去运⾏这些开机启动的程序。但是,不同的场合需要启动不同的程序,⽐如⽤作服务器时,需要启动Apache,⽤作桌⾯就不需要。Linux允许为不同的场合,分配不同的开机启动程序,这就叫做""(runlevel)。也就是说,启动时根据"运⾏级别",确定要运⾏哪些程序。
Linux预置七种运⾏级别(0-6)。⼀般来说,0是关机,1是单⽤户模式(也就是维护模式),6是重启。运⾏级别2-5,各个发⾏版不太⼀样,对于Debian来说,都是同样的多⽤户模式(也就是正常模式)。
init进程⾸先读取⽂件 /etc/inittab,它是运⾏级别的设置⽂件。如果你打开它,可以看到第⼀⾏是这样的:
  id:2:initdefault:
initdefault的值是2,表明系统启动时的运⾏级别为2。如果需要指定其他级别,可以⼿动修改这个值。
那么,运⾏级别2有些什么程序呢,系统怎么知道每个级别应该加载哪些程序呢?......回答是每个运⾏级别在/etc⽬录下⾯,都有⼀个对应的⼦⽬录,指定要加载的程序。
  /etc/rc0.d
  /etc/rc1.d
  /etc/rc2.d
  /etc/rc3.d
  /etc/rc4.d
  /etc/rc5.d
  /etc/rc6.d
上⾯⽬录名中的"rc",表⽰run command(运⾏程序),最后的d表⽰directory(⽬录)。下⾯让我们看看 /etc/rc2.d ⽬录中到底指定了哪些程序。
  $ ls  /etc/rc2.d
  README
  S01motd
  S13rpcbind
  S14nfs-common
  S16binfmt-support
  S16rsyslog
  S16sudo
  S17apache2
  S18acpid
  ...
可以看到,除了第⼀个⽂件README以外,其他⽂件名都是"字母S+两位数字+程序名"的形式。字母S
表⽰Start,也就是启动的意思(启动脚本的运⾏参数为start),如果这个位置是字母K,就代表Kill(关闭),即如果从其他运⾏级别切换过来,需要关闭的程序(启动脚本的运⾏参数为stop)。后⾯的两位数字表⽰处理顺序,数字越⼩越早处理,所以第⼀个启动的程序是motd,然后是rpcbing、数字相同时,则按照程序名的字母顺序启动,所以rsyslog会先于sudo启动。
这个⽬录⾥的所有⽂件(除了README),就是启动时要加载的程序。如果想增加或删除某些程序,不建议⼿动修改 /etc/rcN.d ⽬录,最好是⽤⼀些专门命令进⾏管理(参考和)。
第四步、加载开机启动程序
前⾯提到,七种预设的"运⾏级别"各⾃有⼀个⽬录,存放需要开机启动的程序。不难想到,如果多个"运⾏级别"需要启动同⼀个程序,那么这个程序的启动脚本,就会在每⼀个⽬录⾥都有⼀个拷贝。这样会造成管理上的困扰:如果要修改启动脚本,岂不是每个⽬录都要改⼀遍?
Linux的解决办法,就是七个 /etc/rcN.d ⽬录⾥列出的程序,都设为链接⽂件,指向另外⼀个⽬录 /etc/init.d ,真正的启动脚本都统⼀放在这个⽬录中。init进程逐⼀加载开机启动程序,其实就是运⾏这个⽬录⾥的启动脚本。
下⾯就是链接⽂件真正的指向。
  $ ls -l /etc/rc2.d
  README
  S01motd -> ../init.d/motd
  S13rpcbind -> ../init.d/rpcbind
  S14nfs-common -> ../init.d/nfs-common
  S16binfmt-support -> ../init.d/binfmt-support
  S16rsyslog -> ../init.d/rsyslog
  S16sudo -> ../init.d/sudo
  S17apache2 -> ../init.d/apache2
  S18acpid -> ../init.d/acpid
  ...
这样做的另⼀个好处,就是如果你要⼿动关闭或重启某个进程,直接到⽬录 /etc/init.d 中寻启动脚本即可。⽐如,我要重启Apache服务器,就运⾏下⾯的命令:
  $ sudo /etc/init.d/apache2 restart
/etc/init.d 这个⽬录名最后⼀个字母d,是directory的意思,表⽰这是⼀个⽬录,⽤来与程序 /etc/init 区分。
第五步、⽤户登录
开机启动程序加载完毕以后,就要让⽤户登录了。
⼀般来说,⽤户的登录⽅式有三种:
  (1)命令⾏登录
  (2)ssh登录
  (3)图形界⾯登录
这三种情况,都有⾃⼰的⽅式对⽤户进⾏认证。
(1)命令⾏登录:init进程调⽤getty程序(意为get teletype),让⽤户输⼊⽤户名和密码。输⼊完成后,再调⽤login程序,核对密码(Debian还会再多运⾏⼀个⾝份核对程
序/etc/pam.d/login)。如果密码正确,就从⽂件 /etc/passwd 读取该⽤户指定的shell,然后启动这个shell。
(2)ssh登录:这时系统调⽤sshd程序(Debian还会再运⾏/etc/pam.d/ssh ),取代getty和login,然后启动shell。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。