Linux系统启动流程
initialization [ɪˌnɪʃəlaɪ'zeɪʃn] 初始化
内核参数: /usr/share/doc/kernel-doc-VERSION/Documentation
系统初始化流程(内核级别): POST –> BootSequence(BIOS) –> BootLoader(MBR) –> kernel(ramdisk) –> rootfs(readonly) –> /sbin/init
linux系统的组成部分: 内核 + 根文件系统
内核的功能: 进程管理、内存管理、网络协议栈、文件系统、驱动程序、安全功能
IPC: Inetr Process Communication
消息队列、semerphor、shm
socket
运行中的系统环境可分为两层:内核空间、用户空间
用户空间:应用程序(进程或线程)
内核空间:内核代码(系统调用)
内核设计流派:
单内核设计: 把所有功能集成于同一个程序
linux
微内核设计: 每种功能使用一个单独的子系统实现
Windows, Solaris
linux内核特点:
支持模块化: .ko(kernel object) .so(share object)
支持模块运行时动态装载或卸载;
组成部分:
核心文件: /boot/vmlinuz-VERSION-release
ramdisk: 开机加载驱动程序的虚拟根文件系统
CentOS 5: /boot/initrd-VERSION-release.img
CentOS 6,7: /boot/initramfs-VERSION-release.img
模块文件: /lib/modules/VERSION-release
CentOS系统的启动流程:
POST: Power On and Self Test, 加电自检
ROM: COMS
BIOS: Basic Input and Output System
RAM+ROM
Boot Sequence:
按次序查找各引导设备, 第一个有引导程序的设备即为本次启动要用到设备.
bootloader: 引导加载器, 程序
Windows: ntloader
Linux:
LILO: LInux LOader, 现在多数用在手机等小型移动设备
GRUB: Grand Uniform Bootloader
CentOS 5,6: GRUB 0.X :GRUB Legacy
CentOS 7: GRUB 1.X: GRUB2s
功能: 提供一个菜单, 允许用户选择要启动的系统或不同的内核版本; 把用户选定的内核装载到RAM中的特定空间, 解压、展开, 而后把系统的控制权移交给内核.
MBR: Master Boot Record
共512bytes
前446bytes: bootloader
64bytes: 分区列表
2bytes: 结束标志位 55AA
GRUB:
bootloader: 1st stage
partition: filesystem driver, 1.5 stage
partition: /boot/grub, 2nd stage
kernel:
自身初始化
(1) 探测可识别到的所有硬件设备
(2) 加载硬件驱动; (有可能会借助于ramdisk加载驱动)
(3) 以只读方式挂载根文件系统
(4) 运行用户空间的第一个应用程序: /sbin/init
init程序的类型:
CentOS -5: Sysv init
配置文件: /etc/inittab
CentOS 6: Upstart
配置文件: /etc/inittab
主要读取/etc/init/*.conf
CentOS 7: Systemd
配置文件: /usr/lib/systemd/, /etc/systemd/system/
ramdisk:
Linux内核特性之一: 使用缓冲和缓存加速对磁盘上文件的访问
ramdisk –> ramfs
ramdisk: 开机加载驱动程序的虚拟根文件系统
CentOS 5: /boot/initrd-VERSION-release.img
创建工具: mkinitrd
CentOS 6,7: /boot/initramfs-VERSION-release.img
创建工具: dracut, mkinitrd
系统初始化流程(内核级别): POST –> BootSequence(BIOS) –> BootLoader(MBR) –> kernel(ramdisk) –> rootfs(readonly) –> /sbin/init
/sbin/init
CentOS 5: SysV init
运行级别: 为了系统的运行或维护等目的而设定的机制
0-6: 7个级别
0: 关机, shutdown
1: 单用户模式(single user), root用户, 无须认证; 维护模式
2: 多用户模式(multi user), 会启动网络功能, 但不会启动NFS, 维护模式
3: 多用户模式(multi user), 完全功能模式, 只启动文本界面
4: 预留模式, 相当于3级别
5: 多用户模式(multi user), 完全功能模式, 启动图形界面
6: reboot
默认界别: 3, 5
级别切换: init #
级别查看: who -r, runlevel
配置文件: /etc/inittab
每行定义一种action以及与之对应的process
id:runlevels:action:process
id: 一个任务的标识符
runlevels: 在哪些级别启动此任务; #, ###, 也可以为空, 表示所有级别
action: 在什么条件下启动此任务
process: 具体的任务
action:
wait: 等待切换至此任务所在的级别时执行一次
respawn: 一旦此任务终止时就自动重新启动
initdefault: 设定默认运行级别, 此时, process会省略
sysinit: 设定系统初始化方式, 此意一般为指定/etc/rc.d/rc.sysinit脚本
例如:
id:3:initdefault
si::sysyinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
…….
l6:6:wait:/etc/rc.d/rc 6
意味着去启动或关闭/etc/rc.d/rc3.d/目录下的服务脚本所控制的服务
K*: 要停止的服务; K##*, 数字表示优先级, 数字越小越先关闭, 依赖的服务线管理, 被依赖的后关闭
S*: 要启动的服务; S##*, 优先级, 数字越小, 优先启动; 被依赖的服务有限启动, 而依赖的服务后启动
rc脚本的功用: 接受一个运行级别数字为参数
脚本框架:
for srv in /etc/rc.d/rc#.d/K*;do
$srv stop
done
for srv in /etc/rc.d/rc#.d/S*;do
$srv start
done
/etc/init.d/*(/etc/rc.d/init.d/*)脚本执行方式:
# /etc/init.d/SRV_SCRIPT {start|stop|restart|status}
# service SRV_SCIPT {start|stop|restart|status}
chkconfig命令: 管控/etc/init.d/每个服务脚本在各级别下的启动或关闭状态
chkconfig [option] [name]
–add: 添加服务到开机启动
能被添加的脚本服务的格式之一
#!/bin/bash
#
#chkconfog: LLL NN NN
#description
–del: 删除指定的开机启动的服务
–list: 查看指定服务
修改指定的链接类型:
chkconfig [–level LEVES] name <on|off|reset>
注意: 正常级别下, 最后一个启动的服务s99local没有链接至/etc/init.d下的某脚本, 而是链接至了/etc/rc.d/rc.local(/etc/rc.local); 因此, 不便或不需要写为服务脚本的程序期望能自动开机运行时, 直接放置于此脚本文件中即可
虚拟终端列表
tty1:2345:respawn:/usr/sbin/mingetty/tty1
……
tty6:2345:respawn:/usr/sbin/mingetty/tty6
(1)mingetty会调用login程序
(2)打开虚拟终端的程序除了mingetty外, 还有getty等
系统初始化脚本文件: /etc/rc.d/rc.sysinit
(1) 设置主机名
(2) 设置欢迎信息
(3) 激udev和selinux
(4) 挂载/etc/fstab文件中定义的所有文件系统
(5) 检测根文件系统, 并以读写方式重新挂载根文件系统
(6) 设置系统时钟
(7) 根据/etc/sysctl.conf文件的设置, 来设定内核参数
(8) 激活lvm及软raid设备
(9) 激活swap设备
(10) 加载额外设备的驱动程序
(11) 清理操作
总结, 用户空间的启动流程: /sbin/init(/etc/inittab)
设置默认运行级别 –> 运行系统初始化脚本, 完成系统初始化 –> 关闭对应级别下面要停止的服务, 开启对应级别下需要启动的服务. –> 设置登录终端 [–> 启动图形终端]
CentOS 6: upstart
init程序: upstart, 但依然为/sbin/init, 其配置文件/etc/init/*.conf, /etc/inittab(仅用于定义默认运行级别)
注意: *.conf 为upstart风格的配置文件
rcS.conf
rc.conf
start-ttys.conf
CentOS 7: systemd
init程序: systemd
配置文件: /usr/lib/systemd/system/*, /etc/systemd/system/*
完全兼容SysV脚本机制, 因此, service命令依然可用; 不过建议使用systemctl命令来控制服务
# systemctl {start|stop|status|restart} name[.service]
CentOS 6启动流程:
POST –> Boot Sequence(BIOS) –> Boot Loader(MBR) –> kernel(ramdisk) –> rootfs –> switch root –> /sbin/init –> (/etc/inittab, /etc/init/*.conf) –> 设定默认运行级别 –> 系统初始化脚本 –> 关闭和启动对应级别下的服务 –> 启动终端
GRUB(Boot Loader):
grub: GRand Unified Bootloader
grub 0.x: grub legacy
grub 1.x: grub2
grub legacy:
stage 1: mbr
stage 1.5: mbr之后的扇区, 让stage 1中的bootloader能识别stage2所在的分区上的文件系统
stage 2: 存放在磁盘分区(/boot/grub/)
配置文件: /boot/grub/gtub.conf <– /etc/grub.conf
stage2及内核等通常放置于一个基本的磁盘分区;
功用:
(1) 提供菜单、并提供交互式接口
e: 编辑模式,用于编辑菜单
c: 命令模式,交互式接口
(2) 加载用户选择的内核或操作系统
允许传递参数给内核
可以隐藏此菜单
(3) 为菜单提供了保护机制
为编辑菜单进行认证
为启用内核或操作系统进行认证
如何识别设备:
(hd#,#):
hd#: 磁盘编号, 用数字表示, 从2开始编号
#: 分区编号, 用数字表示, 从0开始编号
grub的命令行接口
help: 获取帮助列表
help keyword: 获取关键命令的详细信息
find (hd#,#)/PATH/TO/SOMEFILE: 搜索文件
root (hd#,#): 将选定磁盘分区指定为根
kernel /PATH/TO/KERNEL_FILE: 设定本次启动时用到的内核文件; 额外还可以添加许多内核支持使用的cmdline参数
内核参数: /usr/share/doc/kernel-doc-VERSION/Documentation
例如: init=/path/to/init, selinux=0
initrd /PATH/TO/INITRAMFS_FILE: 设定为选定的内核提供额外文件的ramdisk;
boot: 引导启动选定的内核
手动在grub命令行接口启动系统:
grub> root (hd#,#)
grub> kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE
grub> initrd /initramfs-VERSION-RELEASE.img
grub> boot
配置文件: /boot/grub/grub.conf
/etc/grub.conf
配置项:
default=#: 设定默认启动菜单项; 菜单项(title)编号从0开始
timeout=#: 指定菜单项等待用户选择的时长
splashimage=(hd#,#)/PATH/TO/XPM_FILE: 指明菜单背景图片文件路径
hiddenmenu: 隐藏菜单
password [–md5] STRING: 菜单编辑认证
title TITLE: 定义菜单项"标题", 可出现多次
缩进后用菜单专用项
root (hd#,#): grub查找stage2及kernel文件所在设备分区; 为grub的"根"
kernel /PATH/TO/VMLINUZ_FILE [PARAMETERS]: 启动的内核
initrd /PATH/TO/INITRAMFS_FS: 内核匹配的ramfs文件
password [–md5] STRING: 启动选定的内核或操作系统时进行认证
grub-md5-crypt命令: 手动生成密码串, 直接使用即可
openssl passwd -salt "XXX" -1: 生成加盐的md5密码串
进入单用户模式:
(1) 编辑grub菜单(选定要编辑的title, 而后使用e命令)
(2) 在选定的kernel后附加 1, s, S或single都可以
(3) 在kernel所在行, 键入"b"命令, 进入单用户模式
安装grub – 拷贝定制简单的linux系统
(1)grub-install
grub-install –root-directory=ROOT /dev/disk
步骤:
<1> 添加新硬盘
<2> 磁盘分区, 创建/boot、swap(82)、/ 分区
fdisk –> partx
<3> 格式化稳文件系统 mae2fs -t ext4 /dev/DEVICE
<4> 挂载磁盘 mount /dev/DEV /mnt/boot
<5> 安装grub: grub-install –root-directory=/mnt /dev/DEV
<6> cp必要的软件
cp /boot/vmlinuz-…. /mnt/boot/vmlinuz
cp /boot/initramfs-….img /mnt/boot/initramfs.img
vim /boot/grub/grub.conf
default=0
timeout=5
title CentOS (Express)
root (hd0,0)
kernel /vmlinuz ro root=/dev/sda3 init=/bin/bash
initrd /initramfs.img
<7> 创建文件目录
mkdir /mnt/sysroot
mount /dev/sdb3 /mnt/sysroot
cd /mnt/sysroot
mkdir -pv etc bin sbin lib lib64 mnt sys…
<8> 复制必要文件
cp /bin/bash /mnt/sysroot/bin/
ldd /bin/bash –> 复制bash依赖的库文件
cp bash依赖的库文件到相对应的目录下
<9> 移动此磁盘, 重新创建虚拟机, 测试此系统
……
(2)MBR损坏, 未重启
~]# grub
grub> root (hd#,#)
grub> setup (hd#)
(3) 删除/boot目录下所有文件
修复:
进入救援模式
chroot
mkdir /mnt/cdrom
mount /dev/sr0 /mnt/cdrom
rpm -ivh /mnt/cdrom/Packages/kernel…. –force
grub-install /dev/sda
重启系统, 进入grub模式
grub> root (hd0,0)
grub> kernel /vmlinuz-VERSION-release
grub> initrd /initamfs-VERSION-release
grub> boot
(4) 删除/boot目录和/etc/fstab文件
修复步骤:
<1> 光盘启动, 进入救援模式
<2> 手动查看磁盘大小, 使用命令手动挂载后, 查看磁盘文件内容, 判断出根分区; 通过分区大小判断出/boot分区
<3> 编辑/etc/fstab文件, 添加根分区和/boot分区挂载
<4> 重启系统
<5> 示例(3)
<6> 若根分区是挂载在lvm上面, 首先需要激活lvm逻辑卷
<7> 使用lvscan查看lvm的状态
<8> 使用lvchange -ay, 激活lvm, 然后挂载
Linux Kernel:
CentOS启动流程: POST –> bootloader(BIOS,MBR) –> Kernel(initrd) –> rootfs –> switch_root –> /sbin/init
root (hd0,0)
kernel
initrd
ldd命令: 打印应用程序依赖的二进制文件
ldd [option]… file…
内核设计体系: 单内核、微内核
一、Linux:单内核设计,充分借鉴了微内核体系的设计优点; 为内核引入了模块化机制;
1、内核组成部分:
(1) kernel: 内核核心, 一般为bzimage, 通常为与/boot目录, 名称为vmlinuz-VERSION-release;
(2) kernel object: 内核对象, 即内核模块, 一般放置于/lib/modules/VERSION-release/
注意: 内核模块与内核核心版本必须要严格匹配
[ ]: N
[M]: Module
[*]: Y, 编译进内核核心
内核: 支持动态装载和卸载
(2) ramdisk: 辅助性文件, 非必须, 这取决于内核是否能直接驱动rootfs所在的设备;
可加载的驱动:
目标设备驱动, 例如 SCSI 设备驱动;
逻辑设备驱动, 例如 LVM 设备驱动;
文件系统, 例如 xfs 文件系统;
ramdisk: 是一个简装版的根文件系统; 为了让内核能够找到真正的根文件系统
二、内核信息获取: uname
uname – print system information
uname [OPTION]…
-r: 内核的release号
-n: 主机名称
-a: 显示所有信息
三、模块信息获取和管理:
lsmod – show the status of modules in the Linux Kernel
显示的内容来自/proc/modules
lsmod 显示的格式
模块名称 模块大小 引用次数
modinfo – shwo information about a linux kernel module, 显示内核模块信息
用法:
modinfo [-0] [-F field] [-k kernel] [modulename|filename…]
选项:
-F field: 只显示指定字段的信息
-k Kernel: 显示指定内核版本的信息
-a –author, -d –description, -l –license, -p –parameters, -n –filename
modprobe – add and remove modules from the linux kernel, 从内核中装载和卸载模块
用法:
动态装载或卸载
modprobe [-r] module_name
-r: 卸载, 不加此选项为装载模块
注意: 对正在使用中的内核模块不能随意卸载
depmod – generate modules.dep and map files.
内核模块依赖关系文件的生成工具
模块的装载和卸载的另一组工具
insmod – simple program to insert a module into the linux kernel
用法:
insmod [filename] [module options…]
filename: 模块文件的文件路径
注意: 无法自动解决依赖关系
示例:
lsmod btrfs(查看系统的btrfs模块)
insmod `modinfo -n btrfs`(安装btrfs模块)
modinfo btrfs(显示btrfs模块信息, 查看btrfs所depends的模块)
安装依赖模块:
insmod `modinfo -n raid6_pq`(安装显示的模块存储文件)
insmod `modinfo -n xor`
insmod `modinfo -n zlib_deflate`
lsmod | grep xor (查看依赖的模块是否安装完成)
lsmod | grep btrfs
rmmod – Simple program to remove a module from the linux kernel
用法: rmmod [-f] [-s] [-v] [modulename]
-f, –force:
-s,–syslog: send errors to syslog instead of standard error
-v, –version
注意: 安装模块时, 要由内层往外层安装, 卸载时要由外层向内层卸载
四、ramdisk文件管理
(1)mkinitrd
为当前使用中的内核重新制作ramdisk文件;
mkinitrd [OPTIONS…] [<initrd-image>] <kernel-version>
–with=<module>: 除了默认的模块之外需要被装载至initramfs中的模块;
–preload=<module>: initramfs所提供的模块需要预先装载的模块;
示例:
mv /boot/initramfs-<version>.img /root
mkinitrd /boot/initramfs-`uname -r`.img `uname -r`
mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)
(2)dracut – low-level tool for generating an initramfs image
dracut [OPTIONS…] [<image> [<kernel-vision>]]
示例:
dracut /boot/initramfs-$(uname -r).img $(uname -r)
五、内核信息输出的伪文件系统
/proc:
内核状态及统计信息的输出接口; 同时, 还提供了一个配置接口, /proc/sys;
参数:
只读: 用于实现信息输出, 例如/proc/#/*
可写: 可以接受用户指定一个"新值"来实现对内核某功能或特性的配置, /proc/sys/
修改其值的方式:
/proc/sys:
net/ipv4/ip_forward 相当于 net.ipv4.ip_forward
(1) sysctl
专用于查看或设定/proc/sys/目录下的值的
sysctl – configure kernel parameters at runtime, 在运行时配置内核参数
sysctl [options] [variable[=value]] […]
选项:
-a, –all, 查看所有运行中的内核参数
-w, –write, 改变sysctl设定
-p: 重读/etc/sysctl.conf, /etc/sysctl.d/*.conf 配置文件
查看:
sysctl -a
sysctl variable
cat /proc/sys/PATH/TO/SOME_KERNEL_FILE
修改其值:
sysctl -w variable=value
示例:
改变主机名称
查看: uname -n
更改: sysctl kernel.hostname=NAME
查看: uname -n
参数存放路径: /proc/sys/kernel/hostname
(2) 文件系统命令: cat、echo
查看:
# cat /proc/sys/PATH/TO/SOME_KERNEL_FILE
设定:
# echo "VALUE" > /proc/sys/PATH/TO/SOME_KERNEL_FILE
注意: 上述两种方式的设定仅当前运行内核有效; 重启后失效
配置文件: /etc/sysctl.conf, /etc/sysctl.d/*.conf
立即生效:
可以先修改配置文件,
重读配置文件
立即生效: sysctl -p [/PATH/TO/CONFIG_FILE]
内核参数:
net.ipv4.ip_forward: 核心转发功能
vm.drop_caches: 0, 1, 2
kernel.hostname: 主机名
net.ipv4.icmp_echo_ignore_all: 不略所有主机ping操作
/sys目录:
sysfs: 输出内核识别出的各硬件设备的相关属性信息, 也有内核对硬件特性的可设置参数; 对此些参数的修改, 即可定制硬件设备工作特性;
udev: 通过读取/sys目录下的硬件设备信息按需为各硬件设备创建设备文件; udev是用户空间程序; 专用工具: devadmin, hotplug;
udev为设备创建设备文件时, 会读取其事先定义好的规则文件, 一般在/etc/udev/rule.d/目录下, 以及/usr/lib/udev/rule.d/目录下
启动流程:
POST –> BootSequence(BIOS) –> Bootloader(MBR) –> kernel(ramdisk) –> rootfs –> [switch_root] –> /sbin/init(/etc/inittab, /etc/iniy/*.conf, /usr/lib/systemd/system) –> 设定默认运行级别, 系统初始化, 关机及启动服务, 启动终端[启动图形终端]
grub:
1st stage: mbr
1.5 stage: mbr之后的扇区, 识别真正的第二阶段所在文件系统的驱动程序
2nd stage: /boot/grub/stage2
支持加密: 保护编辑功能, 保护内核
编译内核
程序包的编译安装
./configure, make, make install
前提: 准备好开发环境(开发工具, 开发库), 头文件: /usr/include
原因: 开源,源代码 –> 转换成可执行程序
发行版: 以"通用"的目标
编译内核的前提:
(1) 准备好开发环境
(2) 获取目标主机上硬件设备的相关信息
(3) 获取到目标主机系统功能的相关信息, 例如要启用的文件环境
(4) 获取内核源代码包: www.kernel.org
准备开发环境:
CentOS 6:
包组: Development Tools, Server Platform Development
CemtOS 7:
包组: Development Tools, Server Platform Development
查看是否安装ncurses包: yum list all *ncurses*
获取目标主机上硬件设备的相关信息:
CPU型号:
(1) ~]# cat /proc/cpuinfo
(2) ~]# lscpu
(3) ~]# yum -y install x86info (CentOS 6)
x86info –help
PCI设备:
lspci [-v|-vv(显示详细信息)]
lsusb [-v| -vv]
lsblk
了解全部硬件设备信息
~]# hal-device (硬件抽象墙)(CentOS 6)
内核编译过程:
注意:
(1) 内核.tar文件解压放置在/usr/src目录中
tar xf linux-VERSION-release.tar.xz -C /usr/src
(2) 硬件如要要编译驱动, 默认会到/usr/src下寻找文件名叫linux的目录: 建立软链接 ln -sv linux-V-release linux(注意: 不需要创建linux文件假)
(3) make命令: make help 获取需要的选项
make menuconfig: 图形界面参数选择
[*]: 编译进内核
[M]: 编译成模块
步骤:
获取源代码
展开: tar xf linux-V-r.tar.xz -C /usr/src
cd /usr/src
ln -sv linux-3.10.67 linux(注意: 不需要创建linux文件夹)
make menuconfig(配置内核选项)
make [-j #](编译内核, 可以指定cpu核心数量)
make modules_install(安装内核模块)
make install(安装内核核心)
重启系统, 选择使用新内核
screen命令: 内核编译过程建议使用screen
剥离screen界面: Ctrl+<a -> d>
列出: -ls
连接: -r SCREEN_ID
关闭: 在screen内 exit
过程详细说明:
(1) 配置内核选项 cd /usr/src/linux
复制已安装kernel的配置文件 /boot/config-VERSION-release; 有些版本在/proc/config.gz中
~]# cp /boot/config-3.10-229.e17.x86_64 .config
支持"更新"模式进行配置: 在已有的.config文件基础之上进行"修改"配置;
(a) make config: 基于命令行遍历的方式去进行配置内核中可配置的每个选项
(b) make menuconfig: 基于cureses的文本配置窗口
(c) make gconfig: 基于GTK开发环境的窗口界面; "桌面平台开发"包组
(d) make xconfig: 基于QT开发环境的窗口界面
支持"全新配置"模式进行配置
(a) make defconfig: 基于内核为目标平台提供的"默认" 配置为模板进行配置
(b) make allnoconfig: 所有选项均为"no"
(2) 编译
(a) make [-j #]: 启用多线程编译
(b) 编译内核中的一部分代码:
(I) 只编译某子目录中的相关代码
cd /usr/src/linux
make /path/to/dir
(II) 只编译一个特定的模块
cd /usr/src/linux
make /path/to/dir/file.ko
编译好后, 要将文件复制到系统内核相应模块文件中
编译好的模块在:
/lib/modules/VERSION-release/kernel/
(c) 如何交叉编译
目标平台与当前编译操作所在的平台不同
# make ARCH=arch_name
要获取特定目标平台的使用帮助
# make ARCH_name help
(3) 如何在执行过编译操作的内核源码树上做重新编译
事先清理操作:
# make clean: 清理编译生成的绝大多数文件, 但会保留config, 及编译外部模块所需要的文件
# make mrproper: 清理编译生成的所有文件, 包括配置生成的config文件及某些备份文件
# make distclean: 相当于 mrproper, 额外清理跟中patches以及编辑器备份文件
原创文章,作者:black_fish,如若转载,请注明出处:http://www.178linux.com/47271