【windows内核原理与实现】读书笔记(一)-引导过程(上)

(一).要理解windows的引导过程,可以参考书中下面一张图

(二).ntoskrnl.exe的入口函数:KiSystemStartup,位于base\ntos\ke\i386\newsysbg.asm文件中。

内核初始化分为2个阶段进行,阶段0和阶段1。

阶段0:

0.1.它的目的是为阶段1所用到的基本数据结构建立起来。KiSystemStartup函数首先初始化处理器的状态,包括调整它的IDT,初始化TSS(Task State Segment),构造PCR(Process Control Region)。然后调用HalInitalizeProcess函数,为当前处理器初始化其HAL中的PCR和处理器间中断向量。接着调用KiInitalizeKernel函数,执行内核初始化。最后,当前线程蜕变成一个空闲线程。

0.2.KiInitializeKernel是实际执行内核初始化的函数,其代码位于base\ntos\ke\i386\kernlini.c。它主要是初始化内核数据结构,初始化空闲线程和进程对象,初始化PCR,调用执行体函数ExpInitializeExecutive,最后返回。

0.3.ExpInitializeExecutive函数的代码位于base\ntos\init\initos.c。它调用HalInitSystem以初始化HAL(硬件抽象层),调用ExInitSystem以初始化执行体组件的各种数据结构,调用MmInitSystem以初始化内存管理器和内存池,调用ObInitSystem以初始化对象管理器,调用SeInitSystem以初始化安全子系统,调用PsInitSystem以初始化进程/线程管理器,调用PpInitSystem以初始化即插即用管理器,调用DbgkInitialize以初始化调度子系统。

0.4.经过阶段0的初始化后,就可以提供最基本的服务,系统的线程调度器开始工作。它除了初始化其内部的状态变量,也为初始进程创建一个进程对象,名称为"Idle",还创建了“System”进程和一个系统线程,此系统线程的开始例程为Phase1Initialization函数。此函数不会立即的执行,在阶段0初始化过程中,中断是禁止的。

0.5.KiInitalizeKernel函数返回以后,KiSystemStartup启动中断,将当前的中断请求级别(IRQL)降低到DISPATCH_LEVEL,从而允许线程调度器选择新的线程。因此阶段0初始化完成后,阶段1初始化例程Phase1Initialization得以执行,运行在System进程中的一个系统线程。

阶段1:

1.1.Phase1Initialization函数调用Phase1InitializationDiscard执行阶段1的初始化,然后调用MmZeroPageThread函数,从而蜕变成内存管理器的零页面线程(内存管理器中负责在后台将空闲页面清零的辅助线程)。

1.2.在说明阶段1之前,先了解下多处理器或多核系统中的初始化。可以看以下图,当第一个处理器(引导处理器,或0号处理器,或P0)执行到阶段1初始化时,在Phase1InitializationDiscard的一个特定点上,调用KeStartAllProcessors函数,以启动其它的处理器。这些处理器从KiInitProcessor函数开始执行。

 

1.3.KeStartAllProcessors函数位于base\ntos\ke\i386\allproc.c,它设置KiSystemStartup结束处的KiBarrierWait=1变量,设置屏障,然后依次调用KiInitProcessor函数来启动每个处理器。KiInitProcessor为每个处理器构造一份状态信息(KPROCESSOR_STATE结构),然后调用HalStartNextProcessor启动该处理器。KeStartAllProcessors在启动其它所有处理器后,设置好每个处理器控制块(PRCB)中的相关信息,并同步所有处理器的性能计数器,KiBarrierWait=0,关闭屏障,允许其它处理器进入空闲线程循环。此后其它处理器可以按照线程调度器的选择来运行比空闲线程优先级更高的线程。

1.4.阶段1的初始化是内核的完全初始化,它占据系统初始化过程中相当一部分时间。主函数是Phase1InitializationDiscard,该函数按以下步骤完成其主要功能:

(1).全局变量InitializationPhase=1,标志系统引导过程进行内核的阶段1初始化。

(2).调用HalInitSystem,执行HAL阶段1的初始化。

(3).初始化图形引导驱动系统,显示Windows启动屏幕,设置引导进度条范围【0-100】。

(4).调用PoInitSystem,完成电源管理器的阶段0初始化。

(5).调用HalQueryRealTimeClock,初始化系统时间,它必须在HAL阶段1的初始化之后进行,再调用KeSetSystemTime设置系统内核时间。

(6).调用KeStartAllProcessors,启动并初始化其它处理器。

(7).调用ObInitSystem,完成对象管理器的阶段1初始化;调用ExInitSystem,完成执行体组件的阶段1初始化;调用KeInitSystem,完成微内核部分初始化;调用KdInitSystem,完成内核调度器的阶段1初始化,调用SeInitSystem完成安全子系统阶段1初始化。

(8).调用InbvUpdateProgressBar,更新进度条至10%。

(9).调用CreateSystemRootLink,创建符号链接“\SystemRoot”。

(10).调用MmInitSystem,完成内存管理器阶段1初始化。

(11).将国家语言支持(NLS)表映射到系统空间中,然后重置翻译表。

(12).调用CcInitializeCacheManager,初始化缓存管理器。

(13).调用CmInitSystem1,初始化配置管理器,建立起基本的注册表对象操作,把引导时获得的数据转变成注册表格式。此时,HKLM\SYSTEM和HKLM\HARDWARE已可以使用,它必须在IO子系统初始化之前完成。

(14).调用CcPfInitializePrefetcher,初始化内核中的预处理器。

(15).进度条更新到15%。

(16).调用FsRtlInitSystem,初始化文件系统支持库(FsRtl)。

(17).调用KdDebuggerInitialize1,kdcom.dll中的调度器初始化。

(18).调用PpInitSystem,初始化即插即用管理器。

(19).进度条更新到20%。

(20).调用LpcInitSystem,初始化LPC子系统。

(21).此时系统时间已正常运行,调用ExInitSystemPhase2,再次初始化执行体组件。

(22).进度条更新范围设置为【25-75%】。

(23).调用IoInitSystem,初始化IO子系统。该函数所做的工作包括:IO子系统中的状态变量初始化、驱动程序对象类型和设备对象类型的创建、加载“引导--启动”类型的驱动程序、加载“系统--启动”类型的驱动程序,以及WMI初始化等。

(24).进度条范围恢复到【0-100%】。

(25).再次调用MmInitSystem,将当前已加载内核模块中的PAGE段标记为“可换页”。

(26).进度条前进到80%。

(27).调用PoInitSystem,完成电源管理器的阶段1初始化。

(28).调用PsInitSystem,完成进程管理器的阶段1初始化。

(29).进度条前进到85%。

(30).调用SeRmInitPhase1,执行安全引用监视器(SRM)的阶段1初始化。包括创建安全引用监视器的命令服务线程。该线程创建一个名为“引用监视器命令端口”的LPC端口,以接收来自lsass.exe进程的命令。

(31).进度条前进到90%。

(32).创建会话管理器子系统进程(smss.exe)。首先准备各种参数信息(RTL_USER_PROCESS_PARAMETERS结构),包括环境参数字符串,然后调用RtlCreateUserProcess函数创建smss进程。

(33).进度条前进到100%。

(34).最后调用ZwWaitForSingleObject函数,在smss进程的句柄上等待,超时值设置为5s。如果等待成功,意味着在5s内 smss 进程退出,于是调用“KeBugCheck(SESSION5_INITIALIZATION_FAILED)”,系统崩溃;若等待超时,则认为会话管理器已经正常运行,于是阶段1初始化完成,当前线程蜕变成零页面线程。

1.5.阶段1初始化完成后,内核已经完全初始化,执行体的各个组件进入正常工作状态。Windows作为一个操作系统,它的引导过程尚未完成,仅仅内核正常工作还不够,系统必须让应用程序也能够运行起来。后续的引导工作由smss进程进行。将在【windows内核原理与实现】读书笔记(一)-引导过程(下)中介绍。

 

posted @ 2019-06-18 09:52  pro_love  阅读(1073)  评论(0编辑  收藏  举报