Linux启动过程简介

来源:互联网 发布:淘宝怎么设置价格区间 编辑:程序博客网 时间:2024/06/12 00:53
在平时工作中用到Linux系统多用到的是一些脚本命令,很少关心Linux核心相关的知识,最近看《Android内核剖析》,里面有少部分介绍Linux内核方面的知识,今天就简要的说说Linux启动相关的工作,后来又查阅了一些资料,《Linux大棚》里介绍Linux启动过程介绍得很详细,我在这里记录下来,以备以后温故学习。

Linux大棚网址:http://roclinux.cn/?p=1301

转载地址:https://www.ibm.com/developerworks/cn/linux/kernel/startup/

Android内核剖析里面说,在系统上电启动时,首先是系统一些硬件设施进行复位,最后复位的是CPU,因为如果CPU最先复位的话,有些其他的设备如总线等未准备好的话,就会报错。在复位完成之后,系统会到固定的地址去读取boot loader引导程序。boot loader引导程序会加载内核程序,启动Linux系统。这里介绍得比较简单,比较详细的启动过程摘自Linux大棚,介绍如下:

1. 加载BIOS(Basic Input Output System)

CPU被设计成一个加电后就从某个特殊的地址开始执行指令,BIOS就存放在这里。BIOS被加载后,就会进行一系列的自检操作,检查有哪些设备,是否正常工作;然后对可用的设备进行一些初始化的工作;最后显示所有安装的PCI设备的一个列表。

计算机必须在最开始找到BIOS,因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。在此之后,计算机心里就有谱了,知道应该去读取哪个硬件设备了。

2. 读取MBR(Master Boot Record)

硬盘分为两部分,第一个部分是MBR(第0磁道第一个扇区的512bytes),第二个部分是真正存放数据的区域。MBR里面存放引导程序BootLoader和磁盘分区表,所以MBR非常重要,一旦MBR区域损坏,硬盘可能就报废了,因为没有磁盘分区表,无法访问数据。当安装Linux系统对硬盘进行分区时,其实并没有在硬盘上做记号,只是修改MBR里面的磁盘分区表,将新的分区信息写入MBR而已。磁盘分区表存放的信息非常简单,就是定义了“第n个磁盘块是从第x个柱面到第y个柱面”。

当BIOS找到制定硬盘的MBR之后,就会将其内容复制到0x7c00地址所在的物理内存中,其实被复制的内容就是Boot Loader,此后,系统就开始跳到这个地址,并开始执行相应的代码。

3. 运行Boot Loader

引导程序有很多,常用的是Lilo和Grub,这两个引导程序各有自己的优缺点。查了一些资料,好像Grub引导程序用得多一些,因为lilo没有交互式的界面、而且不支持网络引导;lilo将关于可以引导的操作系统位置的信息物理上存储在MBR中,这导致如果修改了LILO配置文件,必须将LILO第一阶段引导加载程序重写到MBR,一旦配置文件错误,则系统无法引导,而grub如果配置文件错误,则只是默认转到grub命令行界面。

4. 加载内核

根据grub设定的内核映像所在路径,系统读取内存映像并进行解压,此时,屏幕一般会输出“Uncompressing Linux”的提示。当解压缩内核完成后,屏幕输出“OK, booting the kernel”。当内核映像被装载到RAM后,就开始执行内核的代码,这意味着引导完成,开始进入Linux系统的启动过程。

startup_32函数执行阶段:这个函数为第一个Linux进程(进程0)建立执行环境,初始化段寄存器,为进程0建立内核态堆栈等。最后识别处理器模式,并跳转到start_kernel函数执行。这个阶段运行在保护模式下的段式寻址方式。

start_kernel函数执行阶段:这个阶段才是真正的内核初始化阶段,几乎内核每个部分的初始化工作都是由这个函数完成的,如页表的初始化、系统日期和时间的初始化等。此时系统运行在CPU的特权级,也就是我们常说的内核模式下。start_kernel函数主要完成一些数据结构的初始化,随后进入reset-init0函数调用kernel_thread()为进程1创建init内核线程。(有点疑问,不知道这里的进程0和进程1是不是指的是进程id为0和1的进程,只知道Linux中init进程的进程id为1,所有的孤儿进程都会被进程id为1的init进程收养,进程1是否指的就是进程id为1的init进程呢?)

至此,Linux内核已经建立起来了,基于Linux的程序应该可以正常运行了。

5. 运行系统的第一个进程init

内核被加载后,第一个运行的程序便是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作。

/etc/inittab文件主要设定Linux的运行等级,其设定形式是"id:3:initdefault:”,这就表明Linux需要运行在等级5上。Linux的运行等级设定如下:

#   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)

init进程完成初始化工作,设定好系统运行等级之后,开始执行用户层的文件。

6. init执行rc启动脚本

    init运行用户层启动脚本的执行顺序是:

           /etc/rc.d/rc.sysinit------系统初始化脚本,主要工作包括:设置初始的$PATH变量,配置网络,为虚拟内存启动交换,设置系统的主机名,检查root文件系统以进行必要的修复,检查root文件系统的配额,为root文件系统打开用户和组的配额,以读/写的方式重新装载root文件系统,清除被装载的文件系统表/etc/mtab,把root文件系统输入到mtab,使系统为装入模块做准备等等。
          /etc/rc.d/rcX.d/[KS]*------根据运行级别配置服务。停止以K开头的服务,启动以S开头的服务。如果要在系统启动时执行自己编写的特定脚本,可以将脚本链接到对应的rc目录下去,比如Linux系统运行级别是5的话,就将脚本程序链接到/etc/rc.d/rc5.d/下面去,记得一定要以大写S开头。
          /etc/rc.d/rc.local---------执行本地特殊配置。rc.local就是在一切初始化工作后,Linux留给用户进行个性化的地方。你可以把你想设置和启动的东西放到这里。也就是说,另一种在系统启动时执行自己编写的特定脚本的方法,就是在rc.local中加入相应的执行语句,如“exec yourprog”。
          其它---------不同运行级别的特殊服务

7. getty和login

在rc返回后,init将得到控制,并启动mingetty(见第五节)。mingetty是getty的简化,不能处理串口操作。getty的功能一般包括:

  • 打开终端线,并设置模式
  • 输出登录界面及提示,接受用户名的输入
  • 以该用户名作为login的参数,加载login程序

注:用于远程登录的提示信息位于/etc/issue.net中。

login程序在getty的同一个进程空间中运行,接受getty传来的用户名参数作为登录的用户名。

如果用户名不是root,且存在/etc/nologin文件,login将输出nologin文件的内容,然后退出。这通常用来系统维护时防止非root用户登录。

只有/etc/securetty中登记了的终端才允许root用户登录,如果不存在这个文件,则root可以在任何终端上登录。/etc/usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。

当用户登录通过了这些检查后,login将搜索/etc/passwd文件(必要时搜索 /etc/shadow文件)用于匹配密码、设置主目录和加载shell。如果没有指定主目录,将默认为根目录;如果没有指定shell,将默认为/bin/sh。在将控制转交给shell以前, getty将输出/var/log/lastlog中记录的上次登录系统的信息,然后检查用户是否有新邮件(/usr/spool/mail/{username})。在设置好shell的uid、gid,以及TERM,PATH 等环境变量以后,进程加载shell,login的任务也就完成了。

8. bash

运行级别3下的用户login以后,将启动一个用户指定的shell,以下以/bin/bash为例继续我们的启动过程。

bash是Bourne Shell的GNU扩展,除了继承了sh的所有特点以外,还增加了很多特性和功能。由login启动的bash是作为一个登录shell启动的,它继承了getty设置的TERM、PATH等环境变量,其中PATH对于普通用户为"/bin:/usr/bin:/usr/local/bin",对于root 为"/sbin:/bin:/usr/sbin:/usr/bin"。作为登录shell,它将首先寻找/etc/profile 脚本文件,并执行它;然后如果存在~/.bash_profile,则执行它,否则执行 ~/.bash_login,如果该文件也不存在,则执行~/.profile文件。然后bash将作为一个交互式shell执行~/.bashrc文件(如果存在的话),很多系统中,~/.bashrc都将启动 /etc/bashrc作为系统范围内的配置文件。

当显示出命令行提示符的时候,整个启动过程就结束了。此时的系统,运行着内核,运行着几个核心线程,运行着init进程,运行着一批由rc启动脚本激活的守护进程(如 inetd等),运行着一个bash作为用户的命令解释器。

原创粉丝点击