计算机的启动过程
现代计算机=硬件 + 软件;
因此计算机功能的多样性和灵活性与启动状态的单一性发生了冲突,一方面我们必须通过程序控制使得计算机进入特定工作状态(必须运行启动程序来启动计算机),另一方面在启动硬件前必须假设在一个最安全、通用也是功能最弱的状态,需要逐步设置硬件来提升硬件环境能力。因此我们把这个纠结的过程叫做拉鞋带,简称boot,从这个过程我们也能看出OS的启动是一个逐步释放系统灵活性的过程。
Bootloader
Bootloader是引导加载程序,是系统加电之后运行的第一段软件代码,是在操作系统内核运行之前运行的一段程序;
Bootloader是Booter和Loader的合写:Booter要初始化系统硬件使其运行起来,至少是部分运行起来;Loader是将操作系统映像加载到内存中,并跳转到操作系统的代码运行。
Bootloader的实现严重依赖于具体硬件,所以不可能有一个Booterloader支持所有的CPU、所有的开发板,(因此应该大多数烧在板子上。
计算机的启动过程(MIPS)
U-Boot启动过程分为stage1和stage2两大部分,stage1用汇编语言实现且依赖于CPU体系结构,stage2用C语言,可以实现复杂的功能,并且有更好的可读性和移植性。
MIPS的基本地址空间
在三十二位的操作系统下,程序地址空间(4G)分为四大区域,不同的区域有不同的属性:
我们看到我们之前预习的MIPS地址部分在这里得到了应用,四个部分分别对应不同功能的区域:
kuseg: 这些地址是用户态可用的地址,在有MMU的机器里,这些地址将一概被MMU作转换,除非MMU的设置被建立好,否则这2G的地址是不可用的。(只能在MMU被初始化后使用)
kseg0: 将他们的最高位清零,即可映射到物理地址段 512M(0x00000000 -- 0x1fffffff)。这种映射关系很简单,通常称之为"非转换的"地址区域,几乎全部对这段地址的存取都会通过cache,因此cache设置好之前,不能随便使用这段地址。(只能在cache被初始化后使用)
- 通常一个没有MMU的系统会使用这段地址作为其绝大多数程序和数据的存放位置;
- 对于有MMU的系统,操作系统核心会存放在这个区域。
kseg1: 将这些地址的高三位清零可映射到相应的物理地址上,与kseg0映射的物理地址一样,但kseg1 是非cache存取的.。kseg1是唯一在系统重启时能正常工作的地址空间。(使用这里来启动)
kseg2: 这块区域只能在核心态下使用并且要经过MMU的转换. 在MMU设置好之前,不要存取该区 域。除非在写一个真正的操作系统,否则没有理由用kseg2。有时会看到该区域被分为kseg2和kseg3,意在强调低半部分(kseg2)可供运行在管理态的程序使用。
启动地址
MIPS上电启动时,由于OS尚未接管系统,不能采用TLB 、Cache机制。从MIPS的初始内存划分可知,kseg1是唯一的在系统重启时能正常工作的内存映射地址空间。
MIPS的启动入口地址是0xBFC00000,通过将最高3位清零(&0x1fffffff)的方法,将ROM所在的地址区映射到 物理内存的低端512M(0x00000000 - 0x1FFFFFFF)空间, 也是“非翻译无需转换的”(Unmapped)地址区域。
因此,kseg1是唯一的在系统重启时能正常工作的内存映射地址空间,这也是为什么重新启动时的入口向量是( 0xBFC00000)会在这个区域。这个向量对应的物理地址是0x1FC00000,所以CPU从物理地址0x1FC00000开始取第一条指令,这个地址在硬件上已经确定为FLASH(BIOS)的位置。
MIPS启动过程
进入C代码之后:
调用board.c中的函数board_init_f做一系列初始化;
初始化后,可以对串口和内存进行使用,然后进行内存划分,对堆和栈初始化,并留出u-boot代码大小的空间,把代码从flash上搬到ram上,继续执行。
之后进入board.c的board_init_r函数,在这个函数里初始化 flash, pci 以及外设(比如,网口) ,最后进入命令行或者直接启动Linux kernel。
MIPS下Linux系统的引导过程
Linux启动第一阶段Head.s
Bootloader将 Linux 内核映像拷贝到 RAM 中某个空闲地址处,然后一般有个内存移动操作,将内核移到指定的物理地址处。即内核取得控制权后执行的第一条指令的地址。
Linux 内核启动的第一个阶段 从 /arch/mips/kernel/head.s文件开始的。而此处正是内核入口函数kernel_entry(),该函数是体系结构相关的汇编语言,它首先初始化内核堆栈段,为创建系统中的第一个进程进行准备,接着用一段循环将内核映像的未初始化数据段清零,最后跳转到/init/main.c 中的 start_kernel()初始化硬件平台相关的代码。
Linux启动第二阶段start_kernel
计算机的启动过程(x86)
x86启动过程
BIOS
BIOS设置程序是被固化到电脑主板上的ROM芯片中的一组程序,其主要功能是为电脑提供最底层的、最直接的硬件设置和控制。BIOS通常与硬件系统集成在一起(在计算机主板的ROM或EEPROM中),所以也被称为固件。
BIOS程序存放于一个断电后内容不会丢失的只读存储器中;系统上电或被重置(reset)时,处理器要执行第一条指令的地址会被定位到BIOS的存储器中,让初始化程序开始运行。
在X86系统中,CPU加电后将跳转到BIOS的固定物理地址0xFFFF0。
启动第一步——加载BIOS
BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。
硬件自检:
BIOS代码包含诊断功能,以保证某些重要硬件组件,像是键盘、磁盘设备、输出输入端口等等,可以正常运作且正确地初始化。几乎所有的BIOS都可以选择性地运行CMOS存储器的设置程序;也就是保存BIOS会访问的用户自定义设置数据(时间、日期、硬盘细节,等等)。
现代的BIOS可以让用户选择由哪个设备引导电脑,如光盘驱动器、硬盘、软盘、USB U盘等等。这项功能对于安装操作系统、以CD引导电脑、以及改变电脑找寻开机媒体的顺序特别有用。
启动第二步——读取MBR
硬盘上第0磁头第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,它的大小是512字节,别看地方不大,可里面却存放了预启动信息、分区表信息。
MBR( Master Boot Record )主引导记录包含两部分的内容,前446字节为启动代码及数据;之后则是分区表(DPT, Disk Partition Table),分区表由四个分区项组成,每个分区项数据为16字节,记录了启动时需要的分区参数。这64个字节分布在MBR的第447-510字节。 后面紧接着两个字节AA和55被称为幻数(Magic Number), BIOS读取MBR的时候总是检查最后是不是有这两个幻数,如果没有就被认为是一个没有被分区的硬盘。
X86下Linux系统引导过程
Linux在过程中逐级引导,逐步释放灵活性。
启动第三步——Boot Loader
Boot Loader可以初始化硬件设备、 建立内存空间的映射图 ,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。
GRUB磁盘引导过程
stage1: grub读取磁盘第一个512字节(硬盘的0道0面1扇区,被称为MBR(主引导记录),也称为 bootsect)。MBR由一部分bootloader的引导代码、分区表和魔数三部分组成。(启动的第二步)
Stage1.5: 识别各种不同的文件系统格式。这使得grub识别到文件系统。
stage2: 加载系统引导菜单(/boot/grub/menu.lst或grub.lst),加载内核映像(kernel image)和RAM磁盘initrd(可选)。
启动第四步——加载内核
根据grub设定的内核映像所在路径,系统读取内存映像,并进行解压缩操作。
系统将解压后的内核放置在内存之中,初始化函数并初始化各种设备,完成Linux核心环境的建立。
Bootsect.s
Setup.S
启动第五步——用户层init依据inittab文件来设定运行等级
内核被加载后,第一个运行的程序便是 /sbin/init,该文件会读取/etc/inittab文件, 并依据此文件来进行初始化工作。
/etc/inittab文件最主要的作用就是设定Linux 的运行等级 ,其设定形式是“:id:5:initdefault:” ,这就表明Linux需要运行在等级5上。
启动第六步——init进程执行rc.sysinit
在设定了运行等级后,Linux系统执行的第 一个用户层文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作非常多,包括设定PATH、设定网络配置(/etc/sysconfig/network)、启动swap分区、设定/proc等等。
启动第七步——启动内核模块
具体是依据/etc/modules.conf文件或 /etc/modules.d目录下的文件来装载内核模块。
启动第八步——执行不同运行级别的脚本程序
根据运行级别的不同,系统会运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。
启动第九步——执行/etc/rc.d/rc.local
rc.local就是在一切初始化工作后,Linux留给用户进行个性化的地方。你可以把你想设置和启动的东西放到这里。
启动第十步——执行/bin/login程序 ,进入登录状态
此时,系统已经进入到了等待用户输入username和password的时候了,你已经可以用自己的帐号登入系统了。