一. Bootloader
在 Alpha/AXP平台上引导 Linux通常有两种方法,一种是由 MILO及其他类似的引导程序引导,另一
种是由 Firmware直接引导。MILO功能与 i386平台的 LILO相近,但内置有基本的磁盘驱动程序(如
IDE、SCSI等),以及常见的文件系统驱动程序(如 ext2,iso9660等), firmware有 ARC、SRM
两种形式,ARC具有类 BIOS界面,甚至还有多重引导的设置;而 SRM则具有功能强大的命令行界
面,用户可以在控制台上使用 boot等命令引导系统。ARC有分区(Partition)的概念,因此可以访
问到分区的首扇区;而 SRM只能将控制转给磁盘的首扇区。两种 firmware都可以通过引导 MILO来
引导 Linux,也可以直接引导 Linux的引导代码。
“arch/alpha/boot”下就是制作 Linux Bootloader的文件。“head.S”文件提供了对 OSF PAL/1的
调用入口,它将被编译后置于引导扇区(ARC的分区首扇区或 SRM的磁盘 0扇区),得到控制后初
始化一些数据结构,再将控制转给“main.c”中的 start_kernel(), start_kernel()向控制台输出一些
提示,调用 pal_init()初始化 PAL代码,调用 openboot() 打开引导设备(通过读取 Firmware环境),
调用 load()将核心代码加载到 START_ADDR(见 “include/asm-alpha/system.h”),再将 Firmware
中的核心引导参数加载到 ZERO_PAGE(0) 中,最后调用 runkernel()将控制转给 0x100000的 kernel,
bootloader部分结束。
“arch/alpha/boot/bootp.c”以“main.c”为基础,可代替“main.c”与“head.S” 生成用于 BOOTP
协议网络引导的 Bootloader。
Bootloader中使用的所有“srm_”函数在“arch/alpha/lib/”中定义。
以上这种 Boot方式是一种最简单的方式,即不需其他工具就能引导 Kernel,前提是按照 Makefile
的指导,生成 bootimage文件,内含以上提到的 bootloader以及 vmlinux,然后将 bootimage写入
自磁盘引导扇区始的位置中。
当采用 MILO这样的引导程序来引导 Linux时,不需要上面所说的 Bootloader,而只需要 vmlinux或
vmlinux.gz,引导程序会主动解压加载内核到 0x1000(小内核)或 0x100000(大内核),并直接进
入内核引导部分,即本文的第二节。
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
对于 I386平台
i386系统中一般都有 BIOS做最初的引导工作,那就是将四个主分区
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
中的第一个
可引导分区的第一个扇区加载到实模式地址 0x7c00上,然后将控制转交给它。
在“arch/i386/boot”目录下,bootsect.S是生成引导扇区的汇编源码,它首先将自
己拷贝到 0x90000上,然后将紧接其后的 setup部分(第二扇区)拷贝到 0x90200,
将真正的内核代码拷贝到 0x100000。以上这些拷贝动作都是以 bootsect.S、setup.S
以及 vmlinux在磁盘上连续存放为前提的,也就是说,我们的 bzImage文件或者
zImage文件是按照 bootsect,setup, vmlinux这样的顺序组织,并存放于始于引
导分区的首扇区的连续磁盘扇区之中。
bootsect.S完成加载动作后,就直接跳转到 0x90200,这里正是 setup.S的程序入
口。 setup.S的主要功能就是将系统参数(包括内存、磁盘等,由 BIOS返回)拷
贝到 0x90000-0x901FF内存中,这个地方正是 bootsect.S存放的地方,这时它将
被系统参数覆盖。以后这些参数将由保护模式下的代码来读取。
除此之外,setup.S还将 video.S中的代码包含进来,检测和设置显示器和显示模式。
最后,setup.S将系统转换到保护模式,并跳转到 0x100000(对于 bzImage格式的
大内核是 0x100000,对于 zImage格式的是 0x1000)的内核引导代码,Bootloader
过程结束。
对于 2.4.x版内核
没有什么变化。
二.Kernel引导入口
在 arch/alpha/vmlinux.lds 的 链 接 脚 本 控 制 下 , 链 接 程 序 将 vmlinux 的 入 口 置 于
"arch/alpha/kernel/head.S"中的__start上,因此当 Bootloader跳转到 0x100000时, __start处的代
码开始执行。__start 的代码很简单,只需要设置一下全局变量,然后就跳转到 start_kernel 去了。
start_kernel()是"init/main.c"中的 asmlinkage函数,至此,启动过程转入体系结构无关的通用 C代码
中。
对于 I386平台
在 i386体系结构中,因为 i386本身的问题,在"arch/alpha/kernel/head.S"中需要更
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
多的设置,但最终也是通过 call SYMBOL_NAME(start_kernel)转到 start_kernel()
这个体系结构无关的函数中去执行了。
所不同的是,在 i386系统中,当内核以 bzImage的形式压缩,即大内核方式
(__BIG_KERNEL__)压缩时就需要预先处理 bootsect.S和 setup.S,按照大核模
式使用$(CPP) 处理生成 bbootsect.S和 bsetup.S,然后再编译生成相应的.o文件,
并使用 "arch/i386/boot/compressed/build.c"生成的 build工具,将实际的内核(未
压缩的,含 kernel中的 head.S代码)与"arch/i386/boot/compressed"下的 head.S
和 misc.c合成到一起,其中的 head.S代替了"arch/i386/kernel/head.S"的位置,由
Bootloader引导执行(startup_32入口),然后它调用 misc.c中定义的
decompress_kernel()函数,使用 "lib/inflate.c"中定义的 gunzip()将内核解压到
0x100000,再转到其上执行 "arch/i386/kernel/head.S"中的 startup_32代码。
对于 2.4.x版内核
没有变化。
三.核心数据结构初始化--内核引导第一部分
start_kernel()中调用了一系列初始化函数,以完成 kernel本身的设置。这些动作有的是公共的,有的
则是需要配置的才会执行的。
· 在 start_kernel()函数中,
· 输出 Linux版本信息(printk(linux_banner))
· 设置与体系结构相关的环境(setup_arch())
· 页表结构初始化(paging_init())
· 使用"arch/alpha/kernel/entry.S"中的入口点设置系统自陷入口(trap_init())
· 使用 alpha_mv结构和 entry.S入口初始化系统 IRQ(init_IRQ())
· 核心进程调度器初始化(包括初始化几个缺省的 Bottom-half,sched_init())
· 时间、定时器初始化(包括读取 CMOS时钟、估测主频、初始化定时器中断等,time_init())
· 提取并分析核心启动参数(从环境变量中读取参数,设置相应标志位等待处理,
(parse_options())
· 控制台初始化(为输出信息而先于 PCI初始化,console_init())
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
· 剖析器数据结构初始化(prof_buffer和 prof_len变量)
· 核心 Cache初始化(描述 Cache信息的 Cache,kmem_cache_init())
· 延迟校准(获得时钟 jiffies与 CPU主频 ticks的延迟,calibrate_delay())
· 内存初始化(设置内存上下界和页表项初始值,mem_init())
· 创建和设置内部及通用 cache("slab_cache",kmem_cache_sizes_init())
· 创建 uid taskcount SLAB cache("uid_cache",uidcache_init())
· 创建文件 cache("files_cache",filescache_init())
· 创建目录 cache("dentry_cache",dcache_init())
· 创建与虚存相关的 cache("vm_area_struct","mm_struct",vma_init())
· 块设备读写缓冲区初始化(同时创建"buffer_head"cache用户加速访问,buffer_init())
· 创建页 cache(内存页 hash表初始化,page_cache_init())
· 创建信号队列 cache("signal_queue",signals_init())
· 初始化内存 inode表(inode_init())
· 创建内存文件描述符表("filp_cache",file_table_init())
· 检查体系结构漏洞(对于 alpha,此函数为空,check_bugs())
· SMP机器其余 CPU(除当前引导 CPU)初始化(对于没有配置 SMP的内核,此函数为空,
smp_init())
· 启动 init过程(创建第一个核心线程,调用 init()函数,原执行序列调用 cpu_idle() 等待调度,
init())
至此 start_kernel()结束,基本的核心环境已经建立起来了。
对于 I386平台
i386平台上的内核启动过程与此基本相同,所不同的主要是实现方式。
对于 2.4.x版内核
2.4.x中变化比较大,但基本过程没变,变动的是各个数据结构的具体实现,比如
Cache。
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
四.外设初始化--内核引导第二部分
init()函数作为核心线程,首先锁定内核(仅对 SMP机器有效),然后调用 do_basic_setup()完成外
设及其驱动程序的加载和初始化。过程如下:
· 总线初始化(比如 pci_init())
· 网络初始化(初始化网络数据结构,包括 sk_init()、skb_init()和 proto_init()三部分,在
proto_init()中,将调用 protocols结构中包含的所有协议的初始化过程,sock_init())
· 创建 bdflush 核心线程(bdflush()过程常驻核心空间,由核心唤醒来清理被写过的内存缓冲
区,当 bdflush()由 kernel_thread()启动后,它将自己命名为 kflushd)
· 创建 kupdate核心线程(kupdate()过程常驻核心空间,由核心按时调度执行,将内存缓冲区
中的信息更新到磁盘中,更新的内容包括超级块和 inode表)
· 设置并启动核心调页线程 kswapd(为了防止 kswapd 启动时将版本信息输出到其他信息中
间,核心线调用 kswapd_setup()设置 kswapd运行所要求的环境,然后再创建 kswapd核心
线程)
· 创建事件管理核心线程(start_context_thread()函数启动 context_thread()过程,并重命名为
keventd)
· 设备初始化(包括并口 parport_init()、字符设备 chr_dev_init()、块设备 blk_dev_init()、SCSI
设备 scsi_dev_init()、网络设备 net_dev_init()、磁盘初始化及分区检查等等,device_setup())
· 执行文件格式设置(binfmt_setup())
· 启动任何使用__initcall标识的函数(方便核心开发者添加启动函数,do_initcalls())
· 文件系统初始化(filesystem_setup())
· 安装 root文件系统(mount_root())
至此 do_basic_setup()函数返回 init(),在释放启动内存段(free_initmem())并给内核解锁以后,init()
打开/dev/console设备,重定向 stdin、stdout和 stderr到控制台,最后,搜索文件系统中的 init程序
(或者由 init=命令行参数指定的程序),并使用 execve()系统调用加载执行 init程序。
init()函数到此结束,内核的引导部分也到此结束了,这个由 start_kernel()创建的第一个线程已经成为
一个用户模式下的进程了。此时系统中存在着六个运行实体:
· start_kernel()本身所在的执行体,这其实是一个"手工"创建的线程,它在创建了 init()线程以
后就进入 cpu_idle()循环了,它不会在进程(线程)列表中出现
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
· init线程,由 start_kernel()创建,当前处于用户态,加载了 init程序
· kflushd核心线程,由 init线程创建,在核心态运行 bdflush()函数
· kupdate核心线程,由 init线程创建,在核心态运行 kupdate()函数
· kswapd核心线程,由 init线程创建,在核心态运行 kswapd()函数
· keventd核心线程,由 init线程创建,在核心态运行 context_thread()函数
对于 I386平台
基本相同。
对于 2.4.x版内核
这一部分的启动过程在 2.4.x内核中简化了不少,缺省的独立初始化过程只剩下网
络(sock_init())和创建事件管理核心线程,而其他所需要的初始化都使用__initcall()
宏包含在 do_initcalls()函数中启动执行。
五.init进程和 inittab引导指令
init进程是系统所有进程的起点,内核在完成核内引导以后,即在本线程(进程)空间内加载 init程
序,它的进程号是 1。
init程序需要读取/etc/inittab文件作为其行为指针,inittab是以行为单位的描述性(非执行性)文本,
每一个指令行都具有以下格式:
id:runlevel:action:process其中 id为入口标识符,runlevel为运行级别,action为动作代号,process
为具体的执行程序。
id一般要求 4个字符以内,对于 getty或其他 login程序项,要求 id与 tty的编号相同,否则 getty程
序将不能正常工作。
runlevel是 init所处于的运行级别的标识,一般使用 0-6以及 S或 s。0、1、6运行级别被系统保留,
0作为 shutdown动作,1作为重启至单用户模式,6为重启;S和 s意义相同,表示单用户模式,且
无需 inittab文件,因此也不在 inittab中出现,实际上,进入单用户模式时,init直接在控制台
(/dev/console)上运行/sbin/sulogin。
在一般的系统实现中,都使用了 2、3、4、5几个级别,在 Redhat系统中,2表示无 NFS支持的多
用户模式,3表示完全多用户模式(也是最常用的级别),4保留给用户自定义,5表示 XDM图形登
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
录方式。7-9级别也是可以使用的,传统的 Unix系统没有定义这几个级别。runlevel可以是并列的
多个值,以匹配多个运行级别,对大多数 action来说,仅当 runlevel与当前运行级别匹配成功才会执
行。
initdefault是一个特殊的 action值,用于标识缺省的启动级别;当 init由核心激活以后,它将读取 inittab
中的 initdefault项,取得其中的 runlevel,并作为当前的运行级别。如果没有 inittab文件,或者其中
没有 initdefault项,init将在控制台上请求输入 runlevel。
sysinit、boot、bootwait等 action将在系统启动时无条件运行,而忽略其中的 runlevel,其余的 action
(不含 initdefault)都与某个 runlevel相关。各个 action的定义在 inittab的 man手册中有详细的描
述。
在 Redhat系统中,一般情况下 inittab都会有如下几项:
id:3:initdefault:
#表示当前缺省运行级别为 3--完全多任务模式;
si::sysinit:/etc/rc.d/rc.sysinit
#启动时自动执行/etc/rc.d/rc.sysinit脚本
l3:3:wait:/etc/rc.d/rc 3
#当运行级别为 3时,以 3为参数运行/etc/rc.d/rc脚本,init将等待其返回
0:12345:respawn:/sbin/mingetty tty0
#在 1-5各个级别上以 tty0为参数执行/sbin/mingetty程序,打开 tty0终端用于
#用户登录,如果进程退出则再次运行 mingetty程序
x:5:respawn:/usr/bin/X11/xdm -nodaemon
#在 5级别上运行 xdm程序,提供 xdm图形方式登录界面,并在退出时重新执行
六.rc启动脚本
上一节已经提到 init进程将启动运行 rc脚本,这一节将介绍 rc脚本具体的工作。
一般情况下,rc启动脚本都位于/etc/rc.d目录下,rc.sysinit中最常见的动作就是激活交换分区,检查
磁盘,加载硬件模块,这些动作无论哪个运行级别都是需要优先执行的。仅当 rc.sysinit执行完以后
init才会执行其他的 boot或 bootwait动作。
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
如果没有其他 boot、bootwait动作,在运行级别 3下,/etc/rc.d/rc将会得到执行,命令行参数为 3,
即执行/etc/rc.d/rc3.d/目录下的所有文件。rc3.d下的文件都是指向/etc/rc.d/init.d/目录下各个 Shell脚
本的符号连接,而这些脚本一般能接受 start、stop、restart、status等参数。rc脚本以 start参数启
动所有以 S开头的脚本,在此之前,如果相应的脚本也存在 K打头的链接,而且已经处于运行态了
(以/var/lock/subsys/下的文件作为标志),则将首先启动 K开头的脚本,以 stop作为参数停止这些
已经启动了的服务,然后再重新运行。显然,这样做的直接目的就是当 init改变运行级别时,所有相
关的服务都将重启,即使是同一个级别。
rc程序执行完毕后,系统环境已经设置好了,下面就该用户登录系统了。
七.getty和 login
在 rc返回后,init将得到控制,并启动 mingetty(见第五节)。mingetty是 getty的简化,不能处理
串口操作。getty的功能一般包括:
· 打开终端线,并设置模式
· 输出登录界面及提示,接受用户名的输入
· 以该用户名作为 login的参数,加载 login程序
缺省的登录提示
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
在/etc/issue文件中,但每次启动,一般都会由 rc.local脚本根据系统环境重新生
成。
注:用于远程登录的提示信息位于/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的任务也就完成了。
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com
八.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
作为用户的命令解释器。
附:XDM方式登录
如果缺省运行级别设为 5,则系统中不光有 1-6个 getty监听着文本终端,还有启动了一个 XDM的图
形登录窗口。登录过程和文本方式差不多,也需要提供用户名和口令,XDM 的配置文件缺省为
/usr/X11R6/lib/X11/xdm/xdm-config文件,其中指定了 /usr/X11R6/lib/X11/xdm/xsession作为 XDM
的会话描述脚本。登录成功后,XDM将执行这个脚本以运行一个会话管理器,比如 gnome-session
等。
除了 XDM以外,不同的窗口管理系统(如 KDE和 GNOME)都提供了一个 XDM的替代品,如 gdm
和 kdm,这些程序的功能和 XDM都差不多。
PDF 文件以 "FinePrint pdfFactory Pro" 试用版创建 http://www.pdffactory.com