1.开机流程

 

  1. 载入 BIOS 的硬件信息与进行自我测试,并依据设定取得第一个可开机的设备;
  2. 读取并执行第一个开机设别内 MBR 的 boot Loader (亦即是 grub, spfdisk 等程式);
  3. 依据 boot loader 的设定载入 Kernel ,Kernel 会开始侦测硬件与载入驱动程序;
  4. 在硬件驱动成功后,Kernel 会主动呼叫init程式,而init会取得run-level信息;
  5. init 执行 /etc/rc.d/rc.sysinit文件来准备软件执行的作业环境 (如网路、时区等);
  6. init 根据 run-level 来启动服务 (script方式);
  7. init 执行 /etc/rc.d/rc.local 文件;
  8. init 执行终端机模拟程式 mingetty 来启动 login 程式,最后就等待使用者登入啦;

grub的过程:

开机流程_开机

MBR 使用 Linux 的 grub 这个开机管理程式,并且里面假设已经有了三个选单, 第一个选单可以直接指向 Linux 的核心档案并且直接载入核心来开机;第二个选单可以将开机管理程式控制权交给 Windows 来管理,此时 Windows 的 loader 会接管开机流程,这个时候他就能够启动 windows 了。第三个选单则是使用 Linux 在 boot sector 内的开机管理程式,此时就会跳出另一个 grub 的选单啦

 

2.载入核心

我们可以先看下/boot下面的重要文件

  1. [root@www ~]# ls --format=single-column -F /boot 
  2. config-2.6.18-92.el5      <==此版本核心被编译时选择的功能与模组设定档 
  3. grub/                     <==就是开机管理程式 grub 相关资料目录 
  4. initrd-2.6.18-92.el5.img  <==虚拟档案系统档! 
  5. System.map-2.6.18-92.el5  <==核心功能放置到记忆体位址的对应表 
  6. vmlinuz-2.6.18-92.el5     <==就是核心档案啦!最重要者! 

Linux 核心是可以透过动态载入核心模块的 (就请想成驱动程式即可),这些核心模块就放置在 /lib/modules/ 目录内,但问题是USB, SATA, SCSI... 等硬盘设备的驱动程序通常都是以模块的方式存在的,如果没有SATA的驱动,就无法识别硬盘挂载根目录,也就无法去读取驱动模块。那怎么办呢?可以透过虚拟文件系统来处理这个问题。

 

虚拟文件系统 (Initial RAM Disk) 一般使用的档名为 /boot/initrd ,这个文件的特色是,他也能够透过 boot loader 来载入到记忆体中, 然后这个文件会被解压缩并且在记忆体当中模拟成一个根目录, 且此模拟在内存当中的文件系统能够提供一支可执行的程序,透过该程序来载入开机过程中所最需要的核心模块, 通常这些模块就是 USB, RAID, LVM, SCSI 等文件系统与硬盘介面的驱动程序啦!等载入完成后, 会帮助核心重新呼叫 /sbin/init 来开始后续的正常开机流程

不过,如果用的是IDE硬盘,不需要initrd也可以开机。

 

当核心完整载入后,就要开始执行系统的第一支程序: /sbin/init

 

/sbin/init 最主要的功能就是准备软体执行的环境,包括系统的主机名称、网路设定、语系处理、档案系统格式及其他服务的启动等。 而所有的动作都会透过 init 的设定档,亦即是 /etc/inittab 来规划,而 inittab 内还有一个很重要的设定项目,那就是预设的 runlevel (开机执行等级)

 

run level 分为 7 个等级,分别是:

  • 0 - halt (系统直接关机)
  • 1 - single user mode (单人维护模式,用在系统出问题时的维护)
  • 2 - Multi-user, without NFS (类似底下的 runlevel 3,但无 NFS 服务)
  • 3 - Full multi-user mode (完整含有网路功能的纯文字模式)
  • 4 - unused (系统保留功能)
  • 5 - X11 (与 runlevel 3 类似,但加载使用 X Window)
  • 6 - reboot (重新开机)

/etc/inittab 会使用 /etc/rc.d/rc.sysinit 进行系统初始化,

使用/etc/rc.d/rc N 这个命令来启动不同level下的服务,etc/rc.d/rc 这个文件:

  • 透过外部第一号参数 ($1) 来取得想要执行的脚本目录。亦即由 /etc/rc.d/rc 5 可以取得 /etc/rc5.d/ 这个目录来准备处理相关的脚本程式;
  • 找到 /etc/rc5.d/K??* 开头的档案,并进行‘ /etc/rc5.d/K??* stop ’的动作;
  • 找到 /etc/rc5.d/S??* 开头的档案,并进行‘ /etc/rc5.d/S??* start ’的动作;

/etc/rc5.d/[SK]xx 都是链接文件,其实就是 /etc/init.d/ 相对应的服务脚本

 

使用/etc/rc.d/rc.local来打开使用者自定义开机启动程序

 

开机过程中会使用到的配置文件

/etc/modprobe.conf, 关于模块的,系统自动产生,一般不需要手动修改

/etc/sysconfig/* ,里面有很多配置信息

 

 Run level 的切换

 

  1. 要每次开机都执行某个预设的 run level ,则需要修改 /etc/inittab 内的设定项目, 亦即是‘ id:5:initdefault: ’里头的数字啊;
     
  2. 如果仅只是暂时变更系统的 run level 时,则使用 init [0-6] 来进行 run level 的变更。 但下次重新开机时,依旧会是以 /etc/inittab 的设定为准。

 

 

 

3.核心与核心模块

 

在整个开机的过程当中,是否能够成功的驱动我们主机的硬体配备,是核心 (kernel) 的工作!而核心一般都是压缩档,因此在使用核心之前,就得要将他解压缩后, 才能载入主记忆体当中。

另外,为了应付日新月异的硬体,目前的核心都是具有‘可读取模块化驱动程序’的功能, 亦即是所谓的‘ modules (模块化)’的功能啦!所谓的模组化可以将他想成是一个‘外挂程式’, 该外挂程式可能由硬体开发厂商提供,也有可能我们的核心本来就支援~不过,较新的硬体, 通常都需要硬体开发商提供驱动程式模组啦!

那么核心与核心模块放在哪?

  • 核心: /boot/vmlinuz 或 /boot/vmlinuz-version;
  • 核心解压缩所需 RAM Disk: /boot/initrd (/boot/initrd-version);
  • 核心模块:/lib/modules/version/kernel 或 /lib/modules/$(uname -r)/kernel;
  • 核心原始码: /usr/src/linux 或 /usr/src/kernels/ (要安装才会有,预设不安装)

 

 如果我有个新的硬体,偏偏我的操作系统不支援,该怎么办?很简单啊!

  • 重新编译核心,并加入最新的硬件驱动程序源代码;
  • 将该硬件的驱动程序编译成为模组,在开机时载入该模组

 

核心模组与相依性:

要处理核心模组,自然就得要了解我们核心提供的模块之间的相关性,核心模组的放置处是在 /lib/modules/$(uname -r)/kernel 当中,里面主要还分成几个目录:

  1. arch    :与硬件平台有关的项目,例如 CPU 的等级等等; 
  2. crypto  :核心所支援的加密的技术,例如 md5 或者是 des 等等; 
  3. drivers :一些硬体的驱动程式,例如显示卡、网路卡、PCI 相关硬体等等; 
  4. fs  :核心所支援的 filesystems ,例如 vfat, reiserfs, nfs 等等; 
  5. lib :一些函式库; 
  6. net :与网路有关的各项协定资料,还有防火墙模组 (net/ipv4/netfilter/*) 等等; 
  7. sound   :与音效有关的各项模组; 

 

  1. [root@www ~]# modprobe [-lcfr] module_name 
  2. 选项与参数: 
  3. -c  :列出目前系统所有的模组!(更详细的代号对应表) 
  4. -l  :列出目前在 /lib/modules/`uname -r`/kernel 当中的所有模组完整档名; 
  5. -f  :强制载入该模组; 
  6. -r  :类似 rmmod ,就是移除某个模组啰~ 
  7.  
  8. 范例一:载入 cifs 模组 
  9. [root@www ~]# modprobe cifs 
  10. # 很方便吧!不需要知道完整的模组档名,这是因为该完整档名已经记录到 
  11. # /lib/modules/`uname -r`/modules.dep 当中的缘故啊!如果要移除的话: 
  12. [root@www ~]# modprobe -r cifs 

/lib/modules/$(uname -r)/modules.dep 这个档案记录了在核心支援的模组的各项相依性。利用 depmod 这个指令可以建立(更新)该档案

  1. [root@www ~]# depmod [-Ane] 
  2. 选项与参数: 
  3. -A  :不加任何参数时, depmod 会主动的去分析目前核心的模组,并且重新写入 
  4.       /lib/modules/$(uname -r)/modules.dep 当中。若加入 -A 参数时,则 depmod 
  5.       会去搜寻比 modules.dep 内还要新的模组,如果真找到新模组,才会更新。 
  6. -n  :不写入 modules.dep ,而是将结果输出到萤幕上(standard out); 
  7. -e  :显示出目前已载入的不可执行的模组名称 
  8.  
  9. 范例一:若我做好一个网路卡驱动程式,档名为 a.ko,该如何更新核心相依性? 
  10. [root@www ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net 
  11. [root@www ~]# depmod 

 

核心模块的观察:

查看目前核心载入了多少的模块 :lsmod

查看模块的详细信息

  1. [root@www ~]# modinfo [-adln] [module_name|filename] 
  2. 选项与参数: 
  3. -a  :仅列出作者名称; 
  4. -d  :仅列出该 modules 的说明 (description); 
  5. -l  :仅列出授权 (license); 
  6. -n  :仅列出该模组的详细路径。 

 

核心模块的载入与移除:

insmod和rmmod两个命令可以载入和移除,但是insmod不会分析模块的依赖关系,而且这两个命令必须要自行找到模组的完整档名才行,不是很方便。

  1. [root@www ~]# modprobe [-lcfr] module_name 
  2. 选项与参数: 
  3. -c  :列出目前系统所有的模组!(更详细的代号对应表) 
  4. -l  :列出目前在 /lib/modules/`uname -r`/kernel 当中的所有模组完整档名; 
  5. -f  :强制载入该模组; 
  6. -r  :类似 rmmod ,就是移除某个模组啰~ 
  7.  
  8. 范例一:载入 cifs 模组 
  9. [root@www ~]# modprobe cifs 
  10. # 很方便吧!不需要知道完整的模组档名,这是因为该完整档名已经记录到 
  11. # /lib/modules/`uname -r`/modules.dep 当中的缘故啊!如果要移除的话: 
  12. [root@www ~]# modprobe -r cifs 

因为他是直接去搜寻 modules.dep 的纪录, 所以可以克服模组的相依性问题,而且还不需要知道该模组的详细路径

 

4.Boot Loader: Grub

boot loader 是载入内核的重要工具,没有 boot loader 的话,那么 kernel 根本就没有办法被系统载入。grub是目前最流行的boot loader。

 

在 BIOS 读完信息后,接下来就是会到第一个开机装置的 MBR 去读取 boot loader 了。这个 boot loader 可以具有选单功能、直接载入核心档案以及控制权移交的功能等, 系统必须要有 loader 才有办法载入该作业系统的核心就是了。但是我们都知道, MBR 是整个硬盘的第一个 sector 内的一个区块,充其量整个大小也才 446 bytes 而已。 我们的 loader 功能这么强,光是程序代码与设定资料不可能只占不到 446 bytes 的容量吧?那如何安装?

为了解决这个问题,所以 Linux 将 boot loader 的程序执行与设定值载入分成两个阶段 (stage) 来执行:

  • Stage 1:执行 boot loader 主程序:
    第一阶段为执行 boot loader 的主程式,这个主程式必须要被安装在开机区,亦即是 MBR 或者是 boot sector 。但如前所述,因为 MBR 实在太小了,所以,MBR 或 boot sector 通常仅安装 boot loader 的最小主程式, 并没有安装 loader 的相关设定档;
     
  • Stage 2:主程式载入设定档:
    第二阶段为透过 boot loader 载入所有设定档与相关的环境参数档案 (包括档案系统定义与主要设定档 menu.lst), 一般来说,设定档都在 /boot 底下。

 

 

initrd 的重要性与建立新 initrd 档案:

initrd的目的在于提供开机过程中所需要的最重要核心模组,以让系统开机过程可以顺利完成。 会需要 initrd 的原因,是因为核心模组放置于 /lib/modules/$(uname -r)/kernel/ 当中, 这些模组必须要根目录 (/) 被挂载时才能够被读取。但是如果核心本身不具备磁碟的驱动程式时, 当然无法挂载根目录,也就没有办法取得驱动程式,因此造成两难的地步。

initrd 可以将 /lib/modules/.... 内的‘开机过程当中一定需要的模组’包成一个档案 (档名就是 initrd), 然后在开机时透过主机的 INT 13 硬件功能将该档案读出来解压缩,并且 initrd 在记忆体内会模拟成为根目录。

如果妳有特殊需要所以想重制 initrd 档案的话, 可以使用 mkinitrd 来处理的。

  1. [root@www ~]# mkinitrd [-v] [--with=模组名称] initrd档名 核心版本 
  2. 选项与参数: 
  3. -v  :显示 mkinitrd 的运作过程 
  4. --with=模组名称:模组名称指的是模组的名字而已,不需要填写档名。举例来说, 
  5.        目前核心版本的 ext3 档案系统模组为底下的档名: 
  6.        /lib/modules/$(uname -r)/kernel/fs/ext3/ext3.ko 
  7.        那妳应该要写成: --with=ext3 就好了 (省略 .ko) 
  8. initrd档名:妳所要建立的 initrd 档名,尽量取有意义又好记的名字。 
  9. 核心版本  :某一个核心的版本,如果是目前的核心则是‘ $(uname -r) ’