计算机如何启动(How Computers Boot Up)

来源:互联网 发布:2016我国旅游业数据 编辑:程序博客网 时间:2024/05/24 01:26

原文地址:计算机如何启动(How Computers Boot Up) 作者:itisthinktime

How Comuputers Boot Up

计算机如何引导启动

前面的博文介绍了Intel计算机的底板芯片组与内存映射,为理解计算机引导初始过程打下了基础。引导是一个复杂的、多阶段的、有趣的“东西”。下面是这个过程的简图(outline):

An outline of the boot sequence

当你按下计算机上的电源键时,事情已经开始启动。在加电之后(powered up),底板首先初始化自身固件(firmware----芯片组与其它小部件(tidbits---并试图运行CPU。如果此时运行CPU失败(例如,没有发现CPU或者CPU损坏),那么该计算机除了转动的风扇之外,一无所用。在发现CPU损坏或者缺失的情况下,一些底板会发出蜂鸣报警声,但我最常遇见的情况是只有“旋转风扇的僵尸电脑”。有时USB或者其它设备也会导致此类情况发生:对于之前一直运行良好,而突然出现上述死机状态的计算机,你可以拔掉所有非关键设备,这很可能解决死机问题,然后排除出导致该问题的设备。

如果一切正常,CPU便开始运行。在多处理器(multi-processor)或多核(multi-core)系统中,会动态地选择一个CPU作为引导处理器(BSP:BootTrap Processor),它负责运行所有的BIOS以及内核初始化代码(kernel initialization code)。此时,其它的被称作应用处理器(application processor AP)的CPU仍处于终止状态(halted),直到内核显示地激活它们。Intel CPU已经演化了很多年,但它们是完全后向兼容的(fully backwards compatible)。因而,现代的CPU同最初的1873年的Intel 8086CPU的启动行为非常相似:在加电之后执行相同的动作。在这种原始的加电状态下(primitive power up state),CPU处于实模式(real mode),此时内存映射是禁用的(memory paging disabled),这同古老的MS-DOS时代类似。DOS系统仅能寻址1M字节内存,并且任何代码可以写入内存的任何位置---即不存在保护(protection)或特权(privilege)的概念。

加电之后,CPU内部的寄存器均具有定义好的值(well-defined values),包括指令指针(EPI:instruction pointer),它用于保存CPU将要执行指令的内存地址。Intel CPU加电后仅能够寻址1M内存空间,同时,一个隐含的基址(hidden base address)将应用于EIP,因而,CPU执行的第一条指令位于地址:0xFFFFFFF0。这个魔幻地址被称作重启向量(reset vector),也是现代Intel CPU的标准规格。

底板(motherboard)保证位于重启向量的指令(jump)跳转到映射了BIOS入口的内存地址。跳转指令隐含地(implicitly)清除加电时的隐含基址(hidden base address)。多亏了芯片组(chipsets)保存的内存映射(memory map),使得所有内存地址存储着CPU所需要的正确内容。这些内存映射到包含BIOSflash 内存(flash memory),而此时的RAM模块里面还是一些乱七八糟的东西。相关的内存区域在下图中展示:

                             

Important memory regions during boot

接下来CPU开始执行BIOS代码,该代码初始化计算机上的一些硬件。然后BIOS进行开机自检(Power-on Self Test):检查计算机系统上的各种组件(various components)。缺少可工作的视频卡(working video card)将导致POST失败并终止BIOS,同时发出蜂鸣声告知问题所在,因为此时的视频卡无法工作,所以无法在屏幕上给出一条提示信息。运行中的视频卡将我们带入到了计算机看起来依旧存活的阶段:输出生产商标志,检开始测试内存等等。如果POST失败,例如缺少键盘,将在屏幕输出一条错误信息并终止运行。POST涉及到测试与初始化,包括识别(sorting out)所有资源:中断(interrupts)、内存范围(memory ranges),IO端口(IO Port--PCI设备。现代的BIOS采用“高级配置与电源接口(Advanced Configuration and Power Interface)”的形式,通过构建(build)一些数据表(data tables)来描述计算机上的设备。这些表格在后续为内核所用。

POST之后,BIOS想启动操作系统,而这个操作系统必须在硬盘(hard drives),CD-ROM或者软盘(floppy disk)等上找到。BIOS搜寻启动设备的顺序是由用户配置的。如果没有合适的启动设备,BIOS将终止并给出提示“Non-System Disk or Disk Error.”。一个损坏的硬盘驱动也会导致这种提示。但愿此类情况不再发生,并且BIOS找到可启动的工作磁盘。

BIOS读取硬盘的第一个512字节扇区(sector)(扇区零)。该扇区被称为主引导记录(MBR: Master Boot Record ),它包括两个关键部件(vital components):一个微小的特定操作系统相关的引导程序(OS-specific bootstrapping program),该引导程序位于MBR的开始,其后是磁盘的分区表。BIOS并不关心这些:它将MBR中的内容加载到内存0x7c00处,然后跳转到该位置并执行MBR中的任何代码。

 

Master Boot Record

MBR中的特定代码可以是Windows MBR加载器(loader),也可以是像LILOGRUB之类的Linux加载器,甚至是病毒。分区表(partition table)是标准化的:它是一个64字节的区域,该区域由四条长度为16字节的记录构成,分别用于描述磁盘如何分区(因而你可以运行多操作系统,或者在同样的磁盘拥有单独的卷(separate volumes))。传统上,Microsoft MBR代码主要是查看分区表,找到唯一的活跃分区,并加载该分区对应的启动扇区,然后运行启动扇区上的代码。启动扇区(boot sector )是分区表(partition)的第一个扇区,这与磁盘的第一个扇区相对(as opposed to)。如果分区表发生错误,那么将会得到类似“Invalid Partition Table” 或者 “Missing Operating System.”的提示信息。这条信息并非来自于BIOS,而是来自于从磁盘加载的MBR代码。因而具体信息依赖于MBR

引导加载过程已经变得非常复杂与灵活(sophisticated and flexible)。Linux的引导加载器LILOGRUB可以处理各式各样的操作系统、文件系统与引导配置(boot configuration)。主引导记录(MBR)代码不必按照上述“启动活跃分区(boot the active partition)”的方式组织。但从功能上而言,其过程如下:

1.    MBR本身包含了引导加载器(bootloader)的第一阶段。GRUB将之称为阶段1

2.    由于本身尺寸较小,MBR中的代码仅仅能够从包含了额外自举代码(bootstrap code)的磁盘上加载另一块扇区。该扇区可能是一个分区(partition)的引导扇区(boot sector),也可能是在安装MBR时,通过硬编码(hard-coded)写入了MBR代码的扇区。

3.    之后,MBR代码加上第二步加载的代码读取一个包含bootloader第二阶段的文件。在GRUB中称作GRUB Stage 2。在windows下为:C:\NTLDR。如果在windows下步骤2失败,那么你将得到类似“NTLDR is missing”的信息。然后,阶段二读取启动配置文件(例如,GRUB下的grub.conf,或windows下的boot.ini)。然后向用户展现启动选择,或者启动一个单一系统。

4.    此时bootloader需要启动内核。它必须对文件系统足够的清楚,以便从启动分区(boot partition)读取内核。在Linux下,这意味着读取一个包含了内核的、类似于“vmlinuz-2.6.22-14-server”的文件,将该文件加载如内存,并跳转到内核自举代码。在Windows server 2003,一些内核启动代码已经从内核映像(kernel image)中分离,并通常嵌入在NTLDR之中。在进行一些初始化操作之后,NTDLRc:\Windows\System32\ntoskrnl.exe加载内核映像,并入GRUB所做的一样,跳入内核入口记录。

这里有一个值得一提的并发症(complication)(也就是说,我告诉你这就是hacky)。当前linux内核镜像,即使是压缩过的,也无法在实模式下装入有限的640KB大小的RAM之中。我的vanilla Ubuntu内核压缩之后是1.7M。然而鉴于此时的内核仍然不可用,bootloader必须运行在实模式下,这样才可以调用BIOS程序(BIOS routines)读取磁盘。解决方案就是久负盛名的虚拟模式(unreal mode)。这不是一个真正的处理器模式(希望Intel的工程师喜欢),而是一种技术,它允许计算机在实模式与保护模式(protected mode)之间来回切换以访问1M之上的内存,同时又可用BIOS提供的程序。如果你阅读了GRUB的源代码,你将会发现随处可见的这种转换(see these transitions all over the place)(查看stage2调用的real_to_prot prot_to_real)。在这个复杂过程的最后,bootloader不择手段地将内核加载到内存,它使得内核在实模式下被加载到内存之中。

现在,我们位于第一个图表中所示的从“引导加载器boot loader”跳转到“早期内核初始化”阶段。这也是内核开始投入运转的时机。下面的博文将结合Linux Cross Reference介绍Linux内核的初始化过程。我无法对windows做出同样的事情,但是列出了相应的重点(highlight

0 0
原创粉丝点击