1.开机流程
- 载入 BIOS 的硬件信息与进行自我测试,并依据设定取得第一个可开机的设备;
- 读取并执行第一个开机设别内 MBR 的 boot Loader (亦即是 grub, spfdisk 等程式);
- 依据 boot loader 的设定载入 Kernel ,Kernel 会开始侦测硬件与载入驱动程序;
- 在硬件驱动成功后,Kernel 会主动呼叫init程式,而init会取得run-level信息;
- init 执行 /etc/rc.d/rc.sysinit文件来准备软件执行的作业环境 (如网路、时区等);
- init 根据 run-level 来启动服务 (script方式);
- init 执行 /etc/rc.d/rc.local 文件;
- init 执行终端机模拟程式 mingetty 来启动 login 程式,最后就等待使用者登入啦;
grub的过程:
MBR 使用 Linux 的 grub 这个开机管理程式,并且里面假设已经有了三个选单, 第一个选单可以直接指向 Linux 的核心档案并且直接载入核心来开机;第二个选单可以将开机管理程式控制权交给 Windows 来管理,此时 Windows 的 loader 会接管开机流程,这个时候他就能够启动 windows 了。第三个选单则是使用 Linux 在 boot sector 内的开机管理程式,此时就会跳出另一个 grub 的选单啦
2.载入核心
我们可以先看下/boot下面的重要文件
- [root@www ~]# ls --format=single-column -F /boot
- config-2.6.18-92.el5 <==此版本核心被编译时选择的功能与模组设定档
- grub/ <==就是开机管理程式 grub 相关资料目录
- initrd-2.6.18-92.el5.img <==虚拟档案系统档!
- System.map-2.6.18-92.el5 <==核心功能放置到记忆体位址的对应表
- 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 的切换
- 要每次开机都执行某个预设的 run level ,则需要修改 /etc/inittab 内的设定项目, 亦即是‘ id:5:initdefault: ’里头的数字啊;
- 如果仅只是暂时变更系统的 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 当中,里面主要还分成几个目录:
- arch :与硬件平台有关的项目,例如 CPU 的等级等等;
- crypto :核心所支援的加密的技术,例如 md5 或者是 des 等等;
- drivers :一些硬体的驱动程式,例如显示卡、网路卡、PCI 相关硬体等等;
- fs :核心所支援的 filesystems ,例如 vfat, reiserfs, nfs 等等;
- lib :一些函式库;
- net :与网路有关的各项协定资料,还有防火墙模组 (net/ipv4/netfilter/*) 等等;
- sound :与音效有关的各项模组;
- [root@www ~]# modprobe [-lcfr] module_name
- 选项与参数:
- -c :列出目前系统所有的模组!(更详细的代号对应表)
- -l :列出目前在 /lib/modules/`uname -r`/kernel 当中的所有模组完整档名;
- -f :强制载入该模组;
- -r :类似 rmmod ,就是移除某个模组啰~
- 范例一:载入 cifs 模组
- [root@www ~]# modprobe cifs
- # 很方便吧!不需要知道完整的模组档名,这是因为该完整档名已经记录到
- # /lib/modules/`uname -r`/modules.dep 当中的缘故啊!如果要移除的话:
- [root@www ~]# modprobe -r cifs
/lib/modules/$(uname -r)/modules.dep 这个档案记录了在核心支援的模组的各项相依性。利用 depmod 这个指令可以建立(更新)该档案
- [root@www ~]# depmod [-Ane]
- 选项与参数:
- -A :不加任何参数时, depmod 会主动的去分析目前核心的模组,并且重新写入
- /lib/modules/$(uname -r)/modules.dep 当中。若加入 -A 参数时,则 depmod
- 会去搜寻比 modules.dep 内还要新的模组,如果真找到新模组,才会更新。
- -n :不写入 modules.dep ,而是将结果输出到萤幕上(standard out);
- -e :显示出目前已载入的不可执行的模组名称
- 范例一:若我做好一个网路卡驱动程式,档名为 a.ko,该如何更新核心相依性?
- [root@www ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net
- [root@www ~]# depmod
核心模块的观察:
查看目前核心载入了多少的模块 :lsmod
查看模块的详细信息
- [root@www ~]# modinfo [-adln] [module_name|filename]
- 选项与参数:
- -a :仅列出作者名称;
- -d :仅列出该 modules 的说明 (description);
- -l :仅列出授权 (license);
- -n :仅列出该模组的详细路径。
核心模块的载入与移除:
insmod和rmmod两个命令可以载入和移除,但是insmod不会分析模块的依赖关系,而且这两个命令必须要自行找到模组的完整档名才行,不是很方便。
- [root@www ~]# modprobe [-lcfr] module_name
- 选项与参数:
- -c :列出目前系统所有的模组!(更详细的代号对应表)
- -l :列出目前在 /lib/modules/`uname -r`/kernel 当中的所有模组完整档名;
- -f :强制载入该模组;
- -r :类似 rmmod ,就是移除某个模组啰~
- 范例一:载入 cifs 模组
- [root@www ~]# modprobe cifs
- # 很方便吧!不需要知道完整的模组档名,这是因为该完整档名已经记录到
- # /lib/modules/`uname -r`/modules.dep 当中的缘故啊!如果要移除的话:
- [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 来处理的。
- [root@www ~]# mkinitrd [-v] [--with=模组名称] initrd档名 核心版本
- 选项与参数:
- -v :显示 mkinitrd 的运作过程
- --with=模组名称:模组名称指的是模组的名字而已,不需要填写档名。举例来说,
- 目前核心版本的 ext3 档案系统模组为底下的档名:
- /lib/modules/$(uname -r)/kernel/fs/ext3/ext3.ko
- 那妳应该要写成: --with=ext3 就好了 (省略 .ko)
- initrd档名:妳所要建立的 initrd 档名,尽量取有意义又好记的名字。
- 核心版本 :某一个核心的版本,如果是目前的核心则是‘ $(uname -r) ’