📄 linux启动过程综述.htm
字号:
<!--本网页文件由电子书制作工具“电子文档处理器”未注册版本的Txt2Html功能自动生成 -->
<!-- Made by an Unregistered version of eTextWizard V 1.98-->
<!--“电子文档处理器”软件作者: 冯国华 -->
<!--“电子文档处理器”下载地址: http://www.etextwizard.com/download/ew/etextwizard.exe -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Linux启动过程综述</title>
<META NAME="keywords" CONTENT="电子文档处理器,etextwizard,ebook maker">
<META NAME="description" CONTENT="电子文档处理器是一款文档格式转换、文档处理软件集,批量电子书制作工具,帮助文件及技术资料的快速制作工具。网址:http://www.eTextWizard.com">
<meta name="GENERATOR" content="电子文档处理器,etextwizard">
<style>
<!--
body { line-height: 20px}
td { line-height: 20px}
.Paragraph{ font-size: 9pt }
.9{ font-size: 9pt }
A:link {text-decoration: none; color:#0033CC}
A:visited {text-decoration: none; color: #0033CC}
A:active {text-decoration: none; color: #0000ff }
A:hover {text-decoration: underline; color: #FF0000 }
-->
</style>
</head>
<body bgcolor="#FFFFFF">
<div align="center"><center>
<table border="0" cellpadding="0" cellspacing="0" width="80%">
<tr>
<td width="80%" bgcolor="#000000">
<table border="0" cellspacing="1" width="100%" cellpadding="6" height="98">
<tr>
<td width="100%" bgcolor="#FFFFFD" height="20">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td width="49%"><p class="9"></td>
<td width="51%"><p align="right" class="9"><a href="linux常用命令索引.htm">上一页</a> <a href="index.html">首页</a> <a href="LINUX文件格式简介.htm">下一页</a></td>
</tr>
</table>
</td>
</tr>
<tr bgcolor="#DFE0D1">
<td width="100%" height="21">
<p align="center"><strong>Linux启动过程综述</strong>
</td>
</tr>
<tr bgcolor="#F5F7EE">
<td width="100%" height="51" align=center>
<table><tr><td>
<p class="Paragraph">
我们一起在风雨中前行<br>
<br>
Linux启动过程综述 作者:杨沙洲<br>
<br>
内容:<br>
一. Bootloader<br>
二.Kernel引导入口<br>
三.核心数据结构初始化--内核引导第一部分<br>
四.外设初始化--内核引导第二部分<br>
五.init进程和inittab引导指令<br>
六.rc启动脚本<br>
七.getty和login<br>
八.bash<br>
附:XDM方式登录 作者:杨沙洲<br>
本文以Redhat 6.0 Linux 2.2.19 for Alpha/AXP为平台,描述了从开机到登录的<br>
Linux 启动全过程。该文对i386平台同样适用。<br>
一. Bootloader<br>
在Alpha/AXP平台上引导Linux通常有两种方法,一种是由MILO及其他类似的引导程序引 导,另一种是由Firmware直接引导。MILO功能与i386平台的LILO相近,但内置有基本的磁盘<br>
驱动程序(如IDE、SCSI等),以及常见的文件系统驱动程序(如ext2,iso9660等), firmware有ARC、SRM两种形式,ARC具有类BIOS界面,甚至还有多重引导的设置;而SRM则具<br>
有功能强大的命令行界面,用户可以在控制台上使用boot等命令引导系统。ARC有分区 (Partition)的概念,因此可以访问到分区的首扇区;而SRM只能将控制转给磁盘的首扇区。<br>
两种firmware都可以通过引导MILO来引导Linux,也可以直接引导Linux的引导代码。<br>
“arch/alpha/boot”下就是制作Linux Bootloader的文件。“head.S”文件提供了对<br>
OSF PAL/1的调用入口,它将被编译后置于引导扇区(ARC的分区首扇区或SRM的磁盘0扇区), 得到控制后初始化一些数据结构,再将控制转给“main.c”中的start_kernel(),<br>
start_kernel()向控制台输出一些提示,调用pal_init()初始化PAL代码,调用openboot() 打开引导设备(通过读取Firmware环境),调用load()将核心代码加载到START_ADDR(见<br>
“include/asm-alpha/system.h”),再将Firmware中的核心引导参数加载到ZERO_PAGE(0) 中,最后调用runkernel()将控制转给0x100000的kernel,bootloader部分结束。<br>
<br>
“arch/alpha/boot/bootp.c”以“main.c”为基础,可代替“main.c”与“head.S”<br>
生成用于BOOTP协议网络引导的Bootloader。<br>
Bootloader中使用的所有“srm_”函数在“arch/alpha/lib/”中定义。<br>
<br>
<br>
以上这种Boot方式是一种最简单的方式,即不需其他工具就能引导Kernel,前提是按照 Makefile的指导,生成bootimage文件,内含以上提到的bootloader以及vmlinux,然后将<br>
bootimage写入自磁盘引导扇区始的位置中。<br>
<br>
<br>
当采用MILO这样的引导程序来引导Linux时,不需要上面所说的Bootloader,而只需要 vmlinux或vmlinux.gz,引导程序会主动解压加载内核到0x1000(小内核)或0x100000(大<br>
内核),并直接进入内核引导部分,即本文的第二节。<br>
对于I386平台<br>
i386系统中一般都有BIOS做最初的引导工作,那就是将四个主分区表中的第一个可引导 分区的第一个扇区加载到实模式地址0x7c00上,然后将控制转交给它。<br>
<br>
<br>
<br>
在“arch/i386/boot”目录下,bootsect.S是生成引导扇区的汇编源码,它首先将自己 拷贝到0x90000上,然后将紧接其后的setup部分(第二扇区)拷贝到0x90200,将真正的内核<br>
代码拷贝到0x100000。以上这些拷贝动作都是以bootsect.S、setup.S以及vmlinux在磁盘上 连续存放为前提的,也就是说,我们的bzImage文件或者zImage文件是按照bootsect,setup,<br>
vmlinux这样的顺序组织,并存放于始于引导分区的首扇区的连续磁盘扇区之中。<br>
<br>
<br>
bootsect.S完成加载动作后,就直接跳转到0x90200,这里正是setup.S的程序入口。 setup.S的主要功能就是将系统参数(包括内存、磁盘等,由BIOS返回)拷贝到<br>
0x90000-0x901FF内存中,这个地方正是bootsect.S存放的地方,这时它将被系统参数覆盖。 以后这些参数将由保护模式下的代码来读取。<br>
<br>
<br>
<br>
除此之外,setup.S还将video.S中的代码包含进来,检测和设置显示器和显示模式。最 后,setup.S将系统转换到保护模式,并跳转到0x100000(对于bzImage格式的大内核是<br>
0x100000,对于zImage格式的是0x1000)的内核引导代码,Bootloader过程结束。<br>
对于2.4.x版内核<br>
没有什么变化。<br>
二.Kernel引导入口<br>
<br>
<br>
在arch/alpha/vmlinux.lds的链接脚本控制下,链接程序将vmlinux的入口置于 "arch/alpha/kernel/head.S"中的__start上,因此当Bootloader跳转到0x100000时,<br>
__start处的代码开始执行。__start的代码很简单,只需要设置一下全局变量,然后就跳转 到start_kernel去了。start_kernel()是"init/main.c"中的asmlinkage函数,至此,启<br>
动过程转入体系结构无关的通用C代码中。<br>
对于I386平台<br>
在i386体系结构中,因为i386本身的问题,在"arch/alpha/kernel/head.S"中需要更多的设置,但最终也是通过call<br>
SYMBOL_NAME(start_kernel)转到start_kernel()这个体系结构无关的函数中去执行了。<br>
<br>
<br>
所不同的是,在i386系统中,当内核以bzImage的形式压缩,即大内核方式 (__BIG_KERNEL__)压缩时就需要预先处理bootsect.S和setup.S,按照大核模式使用$(CPP)<br>
处理生成bbootsect.S和bsetup.S,然后再编译生成相应的.o文件,并使用 "arch/i386/boot/compressed/build.c"生成的build工具,将实际的内核(未压缩的,含<br>
kernel中的head.S代码)与"arch/i386/boot/compressed"下的head.S和misc.c合成到一起,其中的head.S代替了"arch/i386/kernel/head.S"的位置,由Bootloader引导执行<br>
(startup_32入口),然后它调用misc.c中定义的decompress_kernel()函数,使用 "lib/inflate.c"中定义的gunzip()将内核解压到0x100000,再转到其上执行<br>
"arch/i386/kernel/head.S"中的startup_32代码。<br>
对于2.4.x版内核<br>
没有变化。<br>
三.核心数据结构初始化--内核引导第一部分<br>
<br>
start_kernel()中调用了一系列初始化函数,以完成kernel本身的设置。 这些动作有的是公共的,有的则是需要配置的才会执行的。<br>
<br>
在start_kernel()函数中,<br>
输出Linux版本信息(printk(linux_banner))<br>
设置与体系结构相关的环境(setup_arch())<br>
页表结构初始化(paging_init())<br>
使用"arch/alpha/kernel/entry.S"中的入口点设置系统自陷入口(trap_init())<br>
使用alpha_mv结构和entry.S入口初始化系统IRQ(init_IRQ())<br>
核心进程调度器初始化(包括初始化几个缺省的Bottom-half,sched_init())<br>
时间、定时器初始化(包括读取CMOS时钟、估测主频、初始化定时器中断等,time_init())<br>
提取并分析核心启动参数(从环境变量中读取参数,设置相应标志位等待处理,(parse_options())<br>
控制台初始化(为输出信息而先于PCI初始化,console_init())<br>
剖析器数据结构初始化(prof_buffer和prof_len变量)<br>
核心Cache初始化(描述Cache信息的Cache,kmem_cache_init())<br>
延迟校准(获得时钟jiffies与CPU主频ticks的延迟,calibrate_delay())<br>
内存初始化(设置内存上下界和页表项初始值,mem_init())<br>
创建和设置内部及通用cache("slab_cache",kmem_cache_sizes_init())<br>
创建uid taskcount SLAB cache("uid_cache",uidcache_init())<br>
创建文件cache("files_cache",filescache_init())<br>
创建目录cache("dentry_cache",dcache_init())<br>
创建与虚存相关的cache("vm_area_struct","mm_struct",vma_init())<br>
<br>
块设备读写缓冲区初始化(同时创建"buffer_head"cache用户加速访问,buffer_init())<br>
创建页cache(内存页hash表初始化,page_cache_init())<br>
创建信号队列cache("signal_queue",signals_init())<br>
初始化内存inode表(inode_init())<br>
创建内存文件描述符表("filp_cache",file_table_init())<br>
检查体系结构漏洞(对于alpha,此函数为空,check_bugs())<br>
SMP机器其余CPU(除当前引导CPU)初始化(对于没有配置SMP的内核,此函数为空,smp_init())<br>
启动init过程(创建第一个核心线程,调用init()函数,原执行序列调用cpu_idle() 等待调度,init())<br>
至此start_kernel()结束,基本的核心环境已经建立起来了。<br>
对于I386平台<br>
i386平台上的内核启动过程与此基本相同,所不同的主要是实现方式。<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -