系统的启动是指从计算机加电到显示用户登陆提示的整个过程。我们将在这里对整个流程以及关系到的一些内容做讨论。过程主要可以分为两个阶段:载入内核和准备运行环境,我们分别进行讨论。本部分的讨论只基于i386硬件架构,但大部分内容是有共通性的。

载入内核(将内核载入内存,并将控制权传递给它)

    计算机加电到Boot Loader开始工作,硬件含量远大于软件含量,所以这里暂不提及,如果实在有关心的朋友,请先别着急,我们将在下期里讨论它。<?XML:NAMESPACE PREFIX = O />
这一阶段是 Boot Loader 的主战场。它必须将可执行的内核映像和内核启动所需的额外数据信息从存储介质上载入内存,这并不是件简单的工作,因为除了从硬盘载入,可能还会需要从网络引导服务器这样的外部介质上载入。各种纷繁芜杂的文件系统类型也给载入带来了巨大的挑战。
Boot Loader 可能还需要改变CPU的运行特权级别,然后就可以让内核投入运行了。
除此之外, Boot Loader 还要完成一些其它功能,比如从BIOS中获取系统信息,或者从启动时的命令行参数中提取信息等。有的 Boot Loader 还要扮演引导选择工具的角色,方便用户选择不同的操作系统。

Boot Loader的职责:

l         判断到底要载入什么,这可以要求用户进行选择
l         载入内核和它可能需要用到的相关数据,比如initrd或者其它参数
l         为内核准备好运行环境,比如,让CPU进入特权模式
l         让内核投入运行

Boot Loader的历史变迁:

早期的Linux只支持软盘引导扇区和 Shoelace 两种 Boot Loader。 Shoelace 是从Minix继承下来的、文件系统相关的 Boot Loader。它只支持 Minix 文件系统。当时Linux只使用 Minix 一种文件系统,所以这样做并没什么问题。可是, Minix 文件系统存在不能保存创建、修改和访问时间信息;文件名长度限制在14个字节等问题。随着Linux的发展,这些与传统Unix文件系统大相径庭的缺陷越来越让人难以忍受,它已经不适合作为Linux的主要文件系统了。
为了支持其它文件系统的实现,Linux引入了VFS(虚拟文件系统)。这个举措很快就引起了热烈的反响,一大批新的文件系统实现出现了。其中一个 Minix 文件系统的变体,扩展文件系统 Xiafs(根据它的作者命名)突破了 Minix 文件系统的文件名长度限制,将此长度一举提高到全部30个字符。当时文件系统之间的竞争着实激烈,很难看出谁会胜出,甚至搞不清楚会不会有一个最终的“赢家”。
       尽管不确定性很大,但是有一点却是清楚的:不管最后哪种文件系统会受到青睐,但是除了 Minix 作为根文件系统,谁也不能从硬盘上启动,因为Shoelace只支持Minix文件系统。LILO应运而生了。由于支持多种文件系统(当时内核支持的主流文件系统已经有 Minix ,扩展文件系统 ext ,Xiafs 。还有人在移植 BSD 的 FFS ,根本看不出来什么时候是个尽头)在实现和维护上难度太大,而Boot Loader 也不应该成为人们试验新的文件系统的绊脚石,所以LILO采取了和文件系统无关的设计。
这种设计经受住了时间的考验,被证明是非常成功的。即使在今天,LILO仍旧可以从内核支持的绝大部分文件系统的硬盘上启动。但是,由于ext2历经了这么长的时间一直没有大的演变,成为了事实上的标准,所以跟文件系统相关的Boot Loader又渐渐流行了起来。
    尽管ext2已经能满足大部分人的日常需要,但是文件系统的设计者们还是在研制以日志机制为特征的新的文件系统,并且已经取得了相当大的进展。考虑到当前又有可能出现多种文件系统的实现同时并存的情况,因此对与文件系统无关的Boot Loader的需求可能会再次变得强劲。

初始化基本的操作环境

一旦内核开始运行,它会初始化内部的数据结构,检测硬件,并且激活相应的驱动程序,为应用软件的准备运行环境。期间包含一个重要操作——应用软件的运行环境必须要有一个文件系统,所以内核必须首先装载root文件系统。由于我们的目的是介绍基本流程,所以相关的硬件初始化细节就不再讨论,相关内容在下一期杂志中会有详细介绍。
硬件初始化完成后,内核着手创建第一个进程——初始进程。说是创建, 其实也不尽然,该进程其实是整个硬件上电初始化过程的延续,只不过执行到这里,进程的逻辑已经完备,所以我们就按照进程的创建方式给它进行了“规格化” ——我们把这个初始进程也叫做“硬件进程”,它会占据进程描述符表的第一个位置,所以可以用task[0][k1] 或INIT_TASK表示。该进程进而会再创建一个新进程去执行init()函数,其实,这个新进程才是系统第一个实际有用的进程,它会负责接着执行下一个阶段的初始化操作; 而初始进程(INIT_TASK)自己则会开始执行idle循环,也就是说,内核初始化完成之后,初始进程唯一的任务就是在没有任何其它进程需要执行的时候, 消耗空闲的CPU时 间(因此初始进程也被称为idle进程)。
下一阶段的初始化工作要比前一阶段轻松一点,因为现在是由一个真正进程来接手负责完成它们了,而前一阶段都是由“硬件进程”手工去做的。在此阶段,这个由INIT_TASK创建的新进程需要初始化总线、网络并启动系统中的各种系统内核后台线程,然后再初始化外设、设置文件格式,在这之后,它要为进入系统做最后的准备——初始化文件系统,安装root文件系统,打开/dev/console设备,重定向stdin、stdout和stderr到控制台,然后搜索文件系统中的init程序,并使用 execve()系统调用加载执行init程序。系统自此进入了用户态。

装载root文件系统

为了装载文件系统,内核需要:1、知道root文件系统位于那个存储介质上;2有访问该种介质的驱动程序。
最常见的情况是,root文件系统是ext2文件系统,位于IDE硬盘上。这种情况下需要的操作很简单:将设备号作为参数给内核就可以了,IDE的设备驱动程序通常都是编译进内核的。
如果内核没有相关介质的驱动程序,问题就会变得更为复杂。而这种情况并不罕见,比如Linux安装盘使用的“通用”内核一般都会碰到这种情况。如果内核把所有支持的硬件的设备驱动程序都包含进来,就会变成一个庞然大物;而且一些驱动程序在检测硬件的时候会影响其它设备。
这个问题可以通过initrd机制解决,它允许在装载实际的root文件系统之前先使用RAM文件系统。除了上述两个原因,引入initrd还可以解决内核的动态合成问题。(详见参考资料一。)
不过,我们应该注意到,initrd在整个启动过程中并不是从来就有的,它可以说是一个插件,为了解决以上问题,而被加入启动过程,像图一所示,Linux系统在启动时也可以不选择它。

为什么要引入initrd?

Linux启动过程中肯定要载入内核镜像,在此过程中有些要素必须考虑:
首先,内核镜像不能太大。由于受到各种硬件和兼容性的限制,Linux的内核镜像不能太大,但是这并不容易做到。Linux内核的核心部分本身就不小了;而且还必须加入会使用到的驱动程序。
其次,要支持尽可能多的硬件设备。我们在启动过程中有一件重要工作:挂载root文件系统,因为进一步的数据和应用软件都在其上,所以我们的内核必须能够访问root文件系统。对于一般用户,如果他们使用IDE硬盘上的ext2文件分区作为root文件系统,不会有什么问题。因为不管是IDE硬盘还是ext2文件系统,它们的驱动肯定会包含在内核镜像自身里面。但是,确实存在一些特殊情况:比如说我们希望发行Linux系统的安装光盘,那么对光盘的驱动,就不一定包含在内核里面了。(有人可能要奇怪了,咦,光盘中的内核镜像不都已经读进来了吗,怎么内核还访问不了光盘呢? 注意,读入内核镜像的是 Boot Loader ,内核并不具备 Boot Loader 的功能。)如果没有光盘的驱动,我们又怎么把光盘里的软件包安装到用户的计算机里呢?把驱动程序预先编译到内核里?听起来还不错,可是如果我们除了光盘还有一些其它的安装介质,那么所有这些驱动就会让内核镜像庞大不堪。
而且,还有更严重的问题,各种不同的驱动程序很有可能会发生冲突,特别是以前ISA设备占市场主导地位的时候,这种冲突简直难以避免。
那时的解决办法是发行商提供预先编译好的支持各种设备的不同内核,把每个内核放进一张软盘,随发行包一起交给用户,用户自己选择装有合适内核的软盘进行引导。或者给用户提供制作引导盘的工具,让用户在安装前制作自己的启动盘。当然,哪一种办法都不能让人满意。
唯一的希望在于使用模块化机制。在内核启动的时候调用相应的模块加载驱动程序,然后访问root文件系统。无论是通过内核对设备做进一步的分析还是直接从用户那里得到配置信息,先配置再加载模块的办法,都能有效地避免冲突的发生。
除了在安装的时候需要在挂载root文件系统之前调用相应的模块之外,在完成安装的系统上,我们可能仍然需要在挂载root文件系统之前调用一些模块。这主要是为给计算机进行配置——一般都要针对不同的计算机进行内核配置。
理想情况下,用户按照自己的实际情况配置编译文件,重新编译内核,一步步完成这种工作。但是没有几个用户喜欢这种冗长并且极易出现错误的工作。而且编译和生成内核需要相应的工具,可是大部分用户不需要这些工具。
在安装的过程中可以直接编译一个整体式的内核,但这并不能很好的解决问题:首先,所有的编译工具还是需要的,其次,编译过程中出现差错导致无法完成任务的概率太大了。所以,我们仍然要使用模块机制:模块机制很可靠,出了错误也只不过不加载对应的模块而已,不会使整个任务失败。而载入模块,像前面说的,也是在挂载root文件系统之前就要得到模块的。
基于以上理由,Linux引入了initrd机制。

initrd做什么

initrd允许系统在启动的时候载入一个RAM盘,这个RAM盘可以被当作一个root文件系统,程序可以在其上运行。(有两重含义,第一,程序在上面;第二,程序的文件系统环境也在上面。)在此之后,可以从别的设备上挂载一个新的root文件系统,先前的root文件系统(initrd)就会被移动到一个目录上去,最终被卸载掉。
为什么要使用RAM盘呢?首先,使用RAM盘能方便的支持以后可能发生的变化;另外,也是为了保持Boot Loader 工作尽可能的简单。在系统引导时,除了内核镜像之外,Boot Loader把所有相关的信息作为一个文件读入内存,内核在启动中将该文件作为一段连续的内存块看待。也就是把它当作RAM盘来 使用了。正因为如此,这种机制被称作“初始 RAM 盘(initial RAM Disk)”,缩写成initrd。
initrd主要用来把系统的启动划分为两个阶段:初始启动的内核只需保留最精简的驱动程序最小集,此后,在启动必须加载附加的模块时,从initrd中加载。

initrd进行的操作

使用initrd的时候,典型的系统启动的流程变为:
1)  Boot Loader读入内核镜像以及initrd文件
2)  内核将initrd文件转成“普通”的RAM盘,并且释放掉initrd文件占用的内存。
3)  initrd被当作root文件系统,以可读可写(read-write)方式安装。
4)  /linuxrc被执行(它可以是任何可执行文件,包括脚本在内;它以uid0身份执行,基本上能完成所有init程序可以做的工作)
5)  linuxrc安装“实际”的root文件系统
6)  linuxrc通过pivot_root系统调用将root文件系统放置在root目录下。
7)  常用的启动流程(比如调用/sbin/init)开始执行。
8)  卸载initrd文件系统。
注意,这是一个典型流程。其实initrd机制可以通过两种方式使用:要么就是作为一个普通的root文件系统使用,这样的话第5、第6两个步骤可以被略过,直接执行/sbin/init(我们的试验系统就是利用这种方法);要么作为一个过渡环境使用,通过它内核可以继续装载“实际”的root文件系统。
-----------------------------------------------------------------

转载于:https://blog.51cto.com/hans925/315286

Linux系统启动的标准流程相关推荐

  1. Linux系统启动任务的写法

    1.到/etc/rc.d目录 # cd /etc/rc.d 2.修改rc.local # vim ./rc.local 你之前是怎么启动nginx和php命令复制即可. 例如: /usr/local/ ...

  2. grub2引导linux内核,一种基于grub2的linux系统启动bootloader的制作方法与流程

    技术领域 本发明涉及服务器应用技术领域,具体涉及一种基于grub2的linux系统启动bootloader的制作方法. 背景技术: 当前linux系统的内核版本已经升级至4.0以上,最新的linux系 ...

  3. Linux系统启动级别及grub配置(一)

    一.Linux系统启动流程 1.首先电脑加电自检,进入到BIOS中,通过MBR装载bootloader,再由bootloader装载内核在内存中完成解压,再将控制权交由内核,内核完成硬件的探测再访问i ...

  4. Linux 系统启动流程及其介绍

    熟悉Linux系统启动流程可以更好的排除Linux系统在启动的过程中所遇到的错误,下面介绍Linux系统在启动过程. 开机,BIOS自检:检测外置设备,目的是为了把外围设备的信息提供给操作系统使用 寻 ...

  5. linux系统启动过程(三)

    Linux 系统启动过程 linux启动时我们会看到许多启动信息. Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行 init. 系统初始化. 建立终端 ...

  6. 图解Linux系统启动流程

    废话不多说,先上图 说明1:上图是Linux系统启动时的详细流程,其中黑色部分为主流程分支,蓝色部分为详细流程分支,绿色部分是注释部分.大家可点击查看大图. 说明2:增加了kernel和initrd间 ...

  7. 【Notes9】Linux系统启动过程,数据库,驱动,i2c-tools,shell

    文章目录 1.Linux系统启动过程:ukr,ubuntu开机引导文件/etc/default/grub 2.数据库:存储过程(PL/SQL代码集,像没有返回值的自定义函数)和函数需要用户显示调用才执 ...

  8. linux系统运行pbs出现ntf,Linux系统启动故障修复

    Linux在启动过程中会出现一些故障,导致系统无法正常启动,本文列举了几个应用单用户模式.GRUB命令操作.Linux救援模式的典型故障修复案例. 一.单用户模式 Linux提供了单用户模式(类似Wi ...

  9. Linux系统启动流程(4)制作自定义linux之一

    Linux系统启动流程(4)制作自定义linux之一 平时使用的服务器类型的linux系统一般都会装载各种软件与服务,而在某些情况下,并不能一直直接使用公司管理的系统,一是可能会出现故障,二是在处理一 ...

  10. linux系统启动故障排除

    linux也会有系统故障,当你好心情启动系统学习时却发生了故障起不来,岂不是很难受:接下来就简单说明系统启不了的问题排查. linux系统是怎样启动的.会经过哪些初始化进程,大致是两个阶段都都是什么? ...

最新文章

  1. LAMP架构之编译安装httpd+(php-fpm)+mariadb
  2. Python函数篇(5)-装饰器及实例讲解
  3. 50本.NTE、C#相关技术书籍免费下载
  4. MVVM模式的3种command总结[2]--RelayCommand
  5. WCF消息之XmlDictionaryWriter
  6. 在Sqoop中管理密码的关键提示
  7. android 代理 wifi热点,android wifi热点默认网关
  8. PYTHON招聘需求与技能体系
  9. 重启openstack服务_如何“ Kubernetize” OpenStack服务
  10. mysql字符型数字 按大小排序,类似if判断函数
  11. 卸载MySQL以及重装卡到Start Services的解决办法(亲测有效,刚重装成功)
  12. python矩阵所有元素取整_Python主要逻辑基础与处理
  13. 程序设计导引及在线实践之时区间时间的转换
  14. HDI与普通PCB的4点主要区别
  15. FreeSWITCH之ESL接口
  16. Symbian 清除栈 CleanupStack
  17. python创建sqlite3 gbk错误_请问django python用sqlite3模拟创建一个服务器时出现错误?...
  18. TryHackMe - Thompson靶场
  19. Pycharm专业版申请免费学生激活连接远程服务器编译配置图片显示变量观察等
  20. 科研速记(2):ICCV19-Wavelet Domain Style Transfer for an Effective Perception-distortion Tradeoff

热门文章

  1. 对图像进行各种滤波的编程思路
  2. 计算机科学技术名家讲座许进,论高校计算机科学与技术课程中存在的问题与改革方向.pdf...
  3. gsettings set org.gnome.desktop.interface scaling-factor 2无效果
  4. org.gradle.api.tasks.compile.CompileOptions.setBootClasspath
  5. 全网首发:configure: error: cannot guess build type; you must specify one
  6. 国产平台不能打印,对LINUX打印的一点疑问
  7. WIN10显示汉字都有问题?
  8. LINUX的VirtualBox安装Windows7
  9. LINUX下载编译jpeglib
  10. 遇到个别手机前置摄像头相差90度的怪事