千难万难启动最难系列(三)
前一篇介绍了NT 5.x的启动过程,本篇将介绍NT 6.x(Windows Vista or Windows 7)的启动过程。
下面首先介绍启动涉及的一些组件:
下面介绍具体的启动过程:
物理磁盘是按扇区(sector)的单元来寻址的,通常情况下,一个硬盘扇区的大小为512B。硬盘的第一个扇区的数据被称为主引导记录(MBR)。MBR包含了固定数量的空间,其中可执行的指令(引导代码)和一章表(分区表)。分区表有4个表项,分别记录了该磁盘的主分区的信息。
BIOS 加载MBR到内存,开始执行MBR的执行代码。MBR的代码开始扫描主分区表,直到一个可引导分区(就是所谓的活动分区)。这种分区被Windows称为引导分区(boot partition),它的第一个扇区称为引导扇区(boot sector),针对引导分区而定义的卷成为系统卷(system volume)。请记住这几个概念,并注意区别分区和卷。MBR将引导扇区代码读入内存,并将控制权交给引导扇区的代码。
这两步跟NT5.x是一样的,只有一个地方有点不同:在系统卷的/Boot/BCD存储了BCD。什么是BCD呢?BCD(Boot Configuration Database)就是启动配置数据库,有点类似NT5.x里面的Boot.ini的作用,只是比Boot.ini更强大。随便说一句,其实Boot.ini在NT6.x里也是可以用的,只是格式跟NT 5.x时代略有不同。
引导扇区的代码的职责是,给Windows提供有关卷的结构和格式方面的信息,并且从该卷的根目录中读入Bootmgr文件(请记住是根目录,因为引导扇区包含的代码恰好足够能够从根目录读取文件)。由于引导扇区含有文件系统格式的代码,所以不同的分区格式的引导扇区代码不同。
引导扇区读入Bootmgr后,控制权交给Bootmgr。此时CPU仍然处于16位实模式,Bootmgr采取的第一个动作是,将系统切到保护模式(protected mode)。但是此时并没有从虚拟地址到物理地址的翻译,这个时候已经可以访问完整的32位内存。在系统进入保护模式后,Bootmgr创建足够的页表使得16M以下的内存通过分页机制可以访问到。最后Bootmgr打开分页机制。带有分页机制的保护模式,正式Windows正常情况执行程序的情况。
进入保护模式后,Bootmgr开始完全起作用。但是它仍然依赖于BIOS提供的函数来访问启动磁盘和显示器。Bootmgr中和BIOS交互的函数会暂时切回到实模式。接着Bootmgr会从系统卷的\Boot目录下读取BCD文件(Bootmgr也内置了文件系统读取代码,而且可以访问子目录)。
Bootmgr下一步会清屏。如果Windows在BCD的设置中通知Bootmgr休眠恢复的话,启动过程会交给Winresume.exe执行。如果BCD中有多个引导项,Bootmgr会显示一个启动选项菜单,如果只有一个启动项,Bootmgr会直接跳过菜单,直接加载Winload.exe.BCD的选项给Bootmgr指出了要加载的系统的系统目录(Windows目录)所在的分区。如果用户在指定时间前没有做出选择的话,Bootmgr会选择默认的启动项。一旦启动项被选择,Bootmgr就会加载Winload.exe。
Bootmgr加载Winload.exe后,控制权交给Winload.exe。Winload.exe包含了从BIOS获取系统基本设备和配置信息的代码。Winload.exe从BIOS搜集的信息最终会被存储在注册表中。
截下来,Winload.exe将从引导卷(boot volume)中加载必要的文件,以便于内核初始化。引导卷就是被引导的系统的系统目录(Windows目录)所在分区的那个卷。Winload.exe将尊需以下几个步骤:
- 加载正确的内核和HAL(通常是Ntoskrnl.exe和Hal.dll),以及它们依赖的文件。
- 读入VGA 字体文件(默认是vgaoem.fon).(这点在NT 5.x里面没有)
- 读取NLS(National Language System)文件用于国际化。默认是l_intl.nls, c_1252.nls,和c_437.nls(这一步也是NT 5.x没有的)
- 读入SYSTEM注册表储槽,以确定需要加载的驱动程序。
- 扫描内存中的SYSTEM注册表储槽,找到所有的引导设备驱动程序。
- 在将要加载的引导驱动程序中,加入为访问系统目录所需的文件系统驱动程序。
- 加载驱动程序
- 准备CPU寄存器,以便于执行Ntoskrnl.exe. 这是Winload在启动过程中最后的任务。
从这里,Winload将调用Ntoskrnl.exe的主函数来完成剩余的系统初始化任务。
Ntosknrl.exe接过控制权后,将完成启动的最后的阶段。在这个过程中差不多40多个小步骤,限于篇幅不再一一赘述。Ntoskrnl最后将启动Smss,Smss负责创建用户模式环境,由用户模式环境向Windows提供可视的界面。
Smss是一个原生应用程序,是操作系统最可信的部分,它并不使用Windows API,因为Smss启动的时候,Windows 子系统尚未执行。Smss会初始化注册表,加载Windows 子系统的内核模式部分(win32k.sys),然后Smss启动子系统进程(包括Windows 子系统Csrss),最后启动Windows初始化进程(Wininit)和登录进程(Winlogon)。
Wininit将完成系统相关的初始化,Winlogon将完成用户登录相关的操作。
总结一下NT 6.x启动流程:MBR->引导扇区代码(boot sector)->Bootmgr->Winload->Ntoskrnl->Smss->Wininit+Winlogon
特别申明:本文参考了 Windows Internals 5th edition