日期:2014-05-16  浏览次数:20712 次

[转]linux的启动

?????????? -------学习Linux时,同事总结的,也许从linux的启动过程可以看出Linux的发展过程;

史前时代:BIOS-计算机的启动过程

  1. 加电 电源加电,主板芯片组像CPU发粗RESET信号,使CPU恢复到初始状态。当芯片组检测到电源开始稳定供电时会撤去RESET信号(松开重启建类似),这是CPU从0xfff0除开始执行指令。该地址位于BIOS寻址范围内。BIOS厂商通常在该地址放一条跳转指令,跳到真正BIOS启动代码除。
  2. 自检 BIOS启动代码首先进行POST(Power-On Self Test,上电自检),POST的主要任务是检测系统中一些关键设备是否存在和能否正常工作, 例如内存和显卡等。如果系统BIOS在POST过程中发现致命错误,如未找到内存或内存有问题(640K内的常规内存),系统会直接控制喇叭报告错误,声音的长短和次数代表错误的类型。
  3. 设备初始化 POST完成后BIOS会查找显卡的BIOS,存放显卡BIOS的ROM芯片的起始地址通常设在0xC0000处,找到显卡BIOS后,调用其初始代码,由显卡BIOS来初始化显卡, 此时多数显卡会在屏幕上显示出一些初始化信息,介绍生产厂商,图形芯片等内容。类似地,BIOS会查找其它设备的BIOS程序,调用这些BIOS内部的初始化代码来初始化相关设备。
  4. 测试设备 查找完所遇其它设备的BIOS之后,系统BIOS将显示自己的启动画面,其中包括系统BIOS类型,序列号和版本号等内容。接着BIOS将检测和显示CPU的类型和工作频率,然后开始测试所有的RAM,并同时在屏幕上显示内存测试的进度。 内存测试通过后,系统BIOS将开始检测系统中安装的一些标准硬件设备,包括硬盘,光驱,串口,并口,软驱等,另外绝大多数较新版本的BIOS在这一过程中回自动检测和设置内存的定时参数,硬盘参数和配置系统中安装的即插即用设备,没找到一个设备之后,BIOS会在屏幕上显示出设备的名称和型号等信息,同时为该设备分配中断,DMA通道和I/O端口。
  5. 更新ESCD 所有硬件检测配置完毕后,多数BIOS会重新清屏,并在屏幕上方显示出一个表格,其中概略的列出系统中安装的各种标准硬件设备,以及他们使用的资源和一些相关工作参数。接下来系统BIOS将更新ESCE(Extended System Configration Data, 扩展系统配置数据)。ESCD是系统BIOS用来与操作系统交换硬件配置信息的一种手段,这些数据被存放在CMOS(Complementary metal oxide Semiconductor,互补金属氧化物半导体)之中。
  6. 启动操作系统 ESCD更新完毕后,系统BIOS的启动代码将进行他的最后一项工作,即根据用户指定的启动顺序从软盘,硬盘或光驱启动操作系统。系统BIOS将启动盘的第一个扇区读入到内存的0x7C00除,并检查0x7dfe地址的内存,如果其内容是0xaa55,跳转到0x7c00处执行MBR(Master Boot Record,主引导记录),MBR从分区表中找到第一个活动分区,按照类似方式读取并执行这个活动分区的引导扇区,该引导扇区负责读取并执行bootloader(windows下C盘中的NTLDR),由bootloader加载系统内核

远古时代:Bootloader

引导装入程序(Bootloader)是BIOS将操作系统内核映像装载到RAM中执行的第一个程序。
软盘启动与磁盘启动过程稍有不同,软盘启动时,BIOS将启动软盘的第一扇区指令装载到RAM中,由于通常现代内核都大于一个扇区大小(512B),因此第一扇区的指令通常是将包含内核映像的扇区加载到RAM中。
从硬盘启动时,硬盘的第一个扇区MBR中包含分区表和一小段程序,这段小程序用来装载被启动的操作系统所在分区的第一个扇区。Win98采用MBR中的小程序加载操作系统内核,而Linux在用一种更灵活的加载方式,bootloader。
Linux2.4及以前的版本,在第一个512字节有一个最小的引导程序,因此在第一扇区拷贝一个内核镜像就可以使软盘启动,但在2.6内核中不再有该引导程序,要想在软盘中启动,必须采用与磁盘类似的方式,在第一个扇区中装入一个引导程序。
Bootloader通常被安装在MBR上代替上面负责引导的小程序。Bootloader通常由于大于一个扇区,会被分为两部分,在BIOS将Bootloader的第一部分加载到RAM的0x00007c00处开始执行,bootloader自己加载到0x00096a00,建立实模式站(0x00098000~0x000969ff),并将bootloader的第二部分装入到0x00096c00开始的RAM中。
第二部分一次从此版读取操作系统映射表,提示给用户,用户可以选择要启动的系统,引动程序将相应分区的引导扇区拷贝到RAM中并执行,或直接将内核拷贝到RAM中。
Bootloader的主要执行过程:

  1. 调用BIOS输出"Loading..."
  2. 调用BIOS从磁盘装入内核映像的第一个扇区(512B),从0x00090000装入RAM,并将setup()函数的代码从0x00090200开始装入RAM。
  3. 调用一个BIOS从磁盘装入其余内核映像,并把内核映像放入从0x00010000(低装载,适用于make zImage的小内核映像)或0x00100000(高装载,make bzImage的大内核映像)
  4. 跳转执行setup()

奴隶社会:setup()

setup()函数有汇编实现放在内核映像文件的偏移量0x200处,bootloader将其装载到0x00090200开始的RAM中。
setup()函数的主要工作是初始化计算机中的硬件设备,并为内核程序的执行建立环境。尽管BIOS已经完成大部分设备的初始化,但是Linux并不依赖与BIOS,而已自己的方式重新初始化设备,以增强可移植性和健壮性。
@TO-DO setup()过程

封建社会:startup_32()

存在两个startup_32函数,setup()的最后是跳转执行的是arch/i386/boot/compressed/head.S中的startup_32(),此时startup_32已经被移动到0x00100000或0x00001000,对应于高装载或低装载。该函数的主要工作是解压内核。
解压完的内核映像从arch/i386/kernel/head.S开始执行。该文件中包含另一个startup_32函数。改startup_32为Linux的第一个进程(pid=0)建立执行环境。
@TO-DO startup_32()过程

民国时代:start_kernel()

startup_32函数最后回跳转执行start_kernel(),start_kernel完成内核初始化工作。start_kernel开始执行后会显示"Linux version 2.6.11..."
该函数中最主要的一个步骤是调用kernel_thread()为进程1创建内核线程。这个线程回创建其它线程并执行/sbin/init程序。该程序会在控制台输出初始化信息,直至最后出现登录提示符,或X登录窗口。通知用户内核已启动,正在运行。

新中国:启动脚本

(该部分只适用Redhat系,如RHEL,CentOS,Fedora等,Debian/Ubuntu启动过程与此不同,后期会有分析)

inittab

/sbin/init(进程1)会利用/etc/inittab获取运行级,并根据不同运行级的配置启动不同的服务项目。
inittab配置文件格式

[设置项目]:[run level]:[init的操作行为]:[命令项目]
设置项目:最多4个字符,表示init的主要目的,就是一个名字
run level:该条目的运行级别
init操作行为:
	主要可选值如下:
		initdefault:表示默认的运行级别值
		sysinit:系统初始化操作项目
		ctrlaltdel:表示[ctrl+alt+del
		wait:表示必须等待后面的命令执行完才可以执行后续操作
		respawn:表示后面的操作会重新启动
命令项目:执行该项目的命令,通常为一个脚本命令
系统初始化(rc.sysinit)

ini