Phase1Initialization 函数分析
Phase1Initialization 函数分析1. 概述Phase1Initialization是内核 Phase 1 初始化的入口线程函数由PsInitSystem在 Phase 0 末尾创建。它运行在一个真正的系统线程上下文中而非空闲线程负责初始化完整的 I/O 系统、加载启动驱动、创建系统进程、最终启动会话管理器 (SMSS)。这个函数永不返回。文件位置: [ntoskrnl/ex/init.c#L2056-L2065](file:///d:/reactos/ntoskrnl/ex/init.c#L2056)VOID NTAPIPhase1Initialization(IN PVOID Context){/* Do the .INIT part of Phase 1 which we can free later */Phase1InitializationDiscard(Context);/* Jump into zero page thread */MmZeroPageThread();}函数只有两行但实际工作委托给Phase1InitializationDiscard约 700 行完成后进入零页线程。2. 函数结构Phase1Initialization(Context) └─ Phase1InitializationDiscard(Context) [约 700 行, CODE_SEG(INIT)] └─ 返回后: └─ MmZeroPageThread() [永不返回]Phase1InitializationDiscard被标记为CODE_SEG(INIT)初始化完成后可被丢弃/回收。3. Phase1InitializationDiscard 执行流程流程图Phase1InitializationDiscard(LoaderBlock) │ ├─ 0. 分配 INIT_BUFFER 设置 Phase 标志 提升线程优先级 │ ├─ 1. HalInitSystem(1, LoaderBlock) ← HAL Phase 1 │ (完整 HAL 初始化: 中断控制器、时钟、DMA 等) │ ├─ 2. 启动视频初始化 │ ├─ 解析 NOGUIBOOT / SOS 选项 │ ├─ InbvDriverInitialize() — 初始化启动视频驱动 │ ├─ 显示启动 Logo (或释放显示所有权) │ └─ 检测 WinPE 模式 (MININT) │ ├─ 3. 显示版本横幅 │ ├─ 从消息表中查找 WINDOWS_NT_BANNER │ ├─ 构建版本字符串 (含 CSDVersion) │ └─ InbvDisplayString() — 在屏幕上打印 │ ├─ 4. 电源初始化 Phase 0 │ └─ PoInitSystem(0) │ ├─ 5. 系统时间初始化 │ ├─ HalQueryRealTimeClock() — 读取 CMOS/RTC │ ├─ Y2K 年号修正 (YEAR 选项) │ ├─ 计算时区偏差 (ExpTimeZoneBias) │ ├─ KeSetSystemTime() — 设置系统时间 │ └─ 记录 KeBootTime │ ├─ 6. [SMP] 启动 AP 处理器 │ ├─ 解析 NUMPROC/BOOTPROC/MAXPROC 选项 │ ├─ KeStartAllProcessors() — 唤醒所有 AP │ └─ HalAllProcessorsStarted() — 等待全部就绪 │ ├─ 7. 显示处理器和内存信息 │ ├─ 打印 N System Processor [M MiB Memory] │ └─ InbvUpdateProgressBar(5) │ ├─ ★ 8. 执行体子系统 Phase 1 初始化 ★ │ ├─ ObInitSystem() — 对象管理器 Phase 1 │ ├─ ExInitSystem() — 执行体初始化 (Worker 线程) │ ├─ KeInitSystem() — 内核调度器 Phase 1 │ ├─ KdInitSystem(1, ...) — 调试器 Phase 1 │ ├─ SeInitSystem() — 安全引用监视器 Phase 1 │ │ │ ├─ InbvUpdateProgressBar(10) │ │ │ ├─ ExpCreateSystemRootLink() — 创建 \??\SystemRoot 符号链接 │ ├─ MmInitSystem(1, ...) — 内存管理器 Phase 1 │ │ (区域映射、段、分页文件) │ ├─ ExpInitNls() — NLS 数据初始化 │ ├─ CcInitializeCacheManager() — 缓存管理器初始化 │ ├─ CmInitSystem1() — 配置管理器 Phase 1 (注册表) │ ├─ CcPfInitializePrefetcher() — 预取器初始化 │ │ │ ├─ InbvUpdateProgressBar(15) │ │ │ ├─ 时区刷新 启动时间校正 │ ├─ FsRtlInitSystem() — 文件系统运行时库 │ ├─ HalReportResourceUsage() — HAL 报告资源使用 │ ├─ KdDebuggerInitialize1() — KD 调试器初始化 │ ├─ PpInitSystem() — PnP 管理器 Phase 1 │ │ │ ├─ InbvUpdateProgressBar(20) │ │ │ ├─ LpcInitSystem() — LPC (本地过程调用) 初始化 │ │ │ ├─ 安全模式检测 BootLog 检测 │ │ │ ├─ InbvUpdateProgressBar(25) │ │ │ ├─ XIPInit() — XIP (就地执行) 初始化 │ └─ InbvSetProgressBarSubset(25, 75) │ ├─ ★ 9. IoInitSystem(LoaderBlock) ★ ← I/O 管理器 (关键!) │ └─ 加载启动驱动、PnP 枚举、创建设备栈 │ ├─ 10. (安全模式时) 注册安全模式配置 │ ├─ 写入 SafeBoot 注册表键 │ └─ 处理 AlternateShell │ ├─ 11. WinPE 模式注册 │ └─ 创建 HKLM\...\Control\MiniNT 键 │ ├─ 12. MmArmInitSystem(2, ...) VDM 初始化 │ └─ InbvUpdateProgressBar(80) │ ├─ 13. PoInitSystem(1) ← 电源管理 Phase 1 │ └─ InbvUpdateProgressBar(90) │ ├─ 14. PsInitSystem(LoaderBlock) ← 进程管理器 Phase 1 │ └─ (创建系统进程、初始化模块加载等) │ ├─ 15. ★ 释放 LoaderBlock ★ │ └─ MmFreeLoaderBlock(LoaderBlock) │ ├─ 16. SeRmInitPhase1() ← 安全引用监视器 Phase 1 │ └─ InbvUpdateProgressBar(100) │ ├─ 17. FinalizeBootLogo() ← 清除启动画面 │ ├─ ★ 18. ExpLoadInitialProcess() ★ ← 启动 SMSS.EXE │ ├─ 构造 SMSS 进程参数 (路径、环境变量) │ ├─ RtlCreateUserProcess() — 创建 smss.exe 进程 │ └─ ZwResumeThread() — 恢复 SMSS 线程执行 │ ├─ 19. ZwWaitForSingleObject(SMSS, 5s)← 等待 SMSS 初始化 │ ├─ STATUS_SUCCESS → SMSS 已终止 → BUGCHECK │ └─ STATUS_TIMEOUT → SMSS 正常运行 → 继续 │ ├─ 20. 清理 │ ├─ ZwClose 进程/线程句柄 │ ├─ 释放环境变量和参数内存 │ ├─ ExpInitializationPhase │ └─ ExFreePoolWithTag(InitBuffer) │ └─ [返回 Phase1Initialization] └─ [进入 MmZeroPageThread 永不返回]4. 函数执行详解4.0 准备工作 (L1374-L1388)InitBufferExAllocatePoolWithTag(NonPagedPool,sizeof(INIT_BUFFER),TAG_INIT);ExpInitializationPhase1;KeSetPriorityThread(KeGetCurrentThread(),HIGH_PRIORITY);分配INIT_BUFFER版本缓冲区、调试缓冲区、进程信息等的容器将全局 Phase 标志设为 1将当前线程优先级提升到最高确保初始化不被其他线程打断4.1 HAL Phase 1 (L1391)if(!HalInitSystem(1,LoaderBlock))KeBugCheck(HAL1_INITIALIZATION_FAILED);HAL Phase 1 的完整初始化与 Phase 0 的轻量初始化不同初始化完整的中断控制器 (PIC/APIC/IOAPIC)时钟定时器校准和配置DMA 控制器初始化HAL 特定的资源报告4.2 启动视频和显示 (L1393-L1428)NoGuiBoot(CommandLinestrstr(CommandLine,NOGUIBOOT));SosEnabled(CommandLinestrstr(CommandLine,SOS));InbvEnableBootDriver(!NoGuiBoot);InbvDriverInitialize(LoaderBlock,IDB_MAX_RESOURCES);if(!NoGuiBoot){InbvEnableDisplayString(SosEnabled);DisplayBootBitmap(SosEnabled);}else{InbvNotifyDisplayOwnershipLost(NULL);InbvEnableDisplayString(FALSE);}InbvDriverInitialize()从 LoaderBlock 中读取启动视频驱动bootvid.dll/lfbbvid.dll初始化显示模式非 NOGUIBOOT 模式显示 ReactOS 启动 LogoSOS 模式在 Logo 上叠加显示模块加载信息NOGUIBOOT 模式释放显示所有权WinPE (LiveCD) 检测—MININT选项设置InitIsWinPEMode TRUE4.3 启动横幅 (L1431-L1517)从内核的 PE 消息资源中查找WINDOWS_NT_BANNER消息条目构建版本字符串KERNEL_VERSION_STR NtBuildLab 版本号 CSDVersionInbvDisplayString()在屏幕上打印4.4 系统时间初始化 (L1519-L1567)PoInitSystem(0);// 电源 Phase 0if(ExCmosClockIsSaneHalQueryRealTimeClock(TimeFields)){if(Y2KHackRequired)TimeFields.Year(CSHORT)YearHack;RtlTimeFieldsToTime(TimeFields,SystemBootTime);// ... 时区计算 ...KeSetSystemTime(UniversalBootTime,OldTime,FALSE,NULL);KeBootTimeUniversalBootTime;}通过 HAL 读取 CMOS/RTC 时间Y2K Hack: 如果启动参数包含YEARXXXX覆盖读取的年份处理 BIOS Y2K Bug根据时区偏差计算本地时间 → 设置系统时间记录KeBootTime供后续使用4.5 AP 处理器启动 (L1569-L1603) [仅 SMP]// 解析 NUMPROC/BOOTPROC/MAXPROCKeStartAllProcessors();// 唤醒 APif(!HalAllProcessorsStarted())KeBugCheck(...);在多处理器系统中在此处唤醒所有应用处理器 (AP)。KeStartAllProcessors发送 IPI 中断使所有 AP 从KiSystemStartup的AppCpuInit自旋等待中释放进入各自的KiSystemStartupBootStack初始化路径。处理器限制选项选项含义NUMPROCN最大逻辑处理器数运行时可动态增加BOOTPROCN启动时最大处理器数MAXPROC报告系统支持的处理器上限4.6 处理器和内存信息显示 (L1605-L1655)N System Processor [M MiB Memory]构建字符串并用InbvDisplayString显示单处理器显示单数多处理器显示复数物理内存大小向上取整到 MiB4.7 执行体子系统 Phase 1 (L1657-L1843)这是最密集的初始化阶段按顺序初始化所有内核子系统函数失败时的 BugCheck职责ObInitSystem()OBJECT1_INITIALIZATION_FAILED对象管理器: 完成对象类型注册ExInitSystem()PHASE1_INITIALIZATION_FAILED执行体: 创建工作线程 (Worker Threads)KeInitSystem()PHASE1_INITIALIZATION_FAILED调度器: 最终初始化KdInitSystem(1, ...)PHASE1_INITIALIZATION_FAILED调试器: 连接调试客户端SeInitSystem()SECURITY1_INITIALIZATION_FAILED安全引用监视器: 审计策略初始化ExpCreateSystemRootLink()SYMBOLIC_INITIALIZATION_FAILED创建\??\SystemRoot→\Device\...MmInitSystem(1, ...)MEMORY1_INITIALIZATION_FAILED内存管理器: 区域映射、段、分页文件ExpInitNls()—加载 NLS 数据到系统CcInitializeCacheManager()CACHE_INITIALIZATION_FAILED缓存管理器: 初始化文件缓存CmInitSystem1()CONFIG_INITIALIZATION_FAILED配置管理器: 完成注册表初始化FsRtlInitSystem()FILE_INITIALIZATION_FAILED文件系统运行时库PpInitSystem()PP1_INITIALIZATION_FAILEDPnP 管理器 Phase 1LpcInitSystem()LPC_INITIALIZATION_FAILEDLPC (本地过程调用)XIPInit()—XIP (eXecute-In-Place) 支持4.8 ★ IoInitSystem — I/O 管理器 (L1849)if(!IoInitSystem(LoaderBlock))KeBugCheck(IO1_INITIALIZATION_FAILED);这是 Phase 1 中最关键的步骤。IoInitSystem的职责IoInitSystem(LoaderBlock) ├── 初始化 I/O 管理器内部数据结构 ├── 为已知设备创建驱动对象 ├── ★ 加载启动时驱动 (Boot Drivers) ★ │ ├── 从注册表 HKLM\...\Services 获取启动驱动列表 │ ├── 加载 \SystemRoot\System32\Drivers\*.sys │ └── 调用驱动 DriverEntry → IoCreateDriver ├── PnP 总线枚举 │ ├── 枚举 PCI/USB/ACPI 总线 │ └── 为发现的设备加载功能驱动 ├── 创建设备栈 (Device Stack) └── 初始化文件系统识别启动驱动的加载顺序由CmpSortDriverListCmpResolveDriverDependencies在 WinLDR 阶段确定按组 (Group) 和标签 (Tag) 排序。4.9 安全模式和 WinPE 注册 (L1855-L1976)安全模式: 在HKLM\...\Control\SafeBoot下创建Option键写入OptionValue(1MINIMAL, 2NETWORK, 3DSREPAIR) 和可选的UseAlternateShell。WinPE 模式: 在HKLM\...\Control下创建MiniNT键标记系统运行在 MiniNT 环境中。4.10 电源 Phase 1 和进程管理器 Phase 1 (L1978-L1996)PoInitSystem(1);// 电源管理 Phase 1 (ACPI 注册等)if(!PsInitSystem(LoaderBlock))KeBugCheck(PROCESS1_INITIALIZATION_FAILED);PsInitSystem(LoaderBlock)Phase 1:完成系统进程 (System PID 4) 的初始化加载内核模式模块 (ntdll.dll, 子系统 DLL 等)准备用户模式进程创建所需的支持结构4.11 释放 LoaderBlock (L1998-L2001)if(LoaderBlockKeLoaderBlock)KeLoaderBlockNULL;MmFreeLoaderBlock(LoaderBlock);释放所有引导加载程序分配的内存。自此以后系统不再依赖 FreeLDR 提供的任何数据和结构——内核已经完全独立。4.12 ★ ExpLoadInitialProcess — 启动 SMSS (L2015-L2017)ExpLoadInitialProcess(InitBuffer,ProcessParameters,Environment);这是 Phase 1 初始化中的最终目标——创建第一个用户模式进程会话管理器 (SMSS)。ExpLoadInitialProcess的详细流程ExpLoadInitialProcess(InitBuffer, ...) │ ├─ 1. 分配进程参数 (ProcessParameters) │ 包含: 当前目录、DLL 搜索路径、映像路径、命令行 │ ├─ 2. 分配环境变量块 (1 页) │ 包含: Path、SystemDrive、SystemRoot │ ├─ 3. 构建 SMSS 映像路径 │ └─ 从 NtInitialUserProcessBuffer 获取 │ (默认: \SystemRoot\System32\smss.exe) │ ├─ 4. ★ RtlCreateUserProcess(\SystemRoot\System32\smss.exe) ★ │ └─ 这不是普通的 CreateProcess: │ ├─ 创建第一个用户模式进程 │ ├─ 初始化 Windows 子系统 (Win32k.sys 初始化由此触发) │ └─ 进程句柄 → ProcessInfo-ProcessHandle │ 线程句柄 → ProcessInfo-ThreadHandle │ ├─ 5. ZwResumeThread() — 恢复 SMSS 主线程 │ (此时 SMSS 开始执行!) │ └─ 6. 返回 Phase1InitializationDiscard4.13 等待 SMSS 和清理 (L2019-L2053)// 等待 5 秒让 SMSS 初始化Timeout.QuadPartInt32x32To64(5,-10000000);// 5 秒StatusZwWaitForSingleObject(ProcessInfo-ProcessHandle,FALSE,Timeout);if(StatusSTATUS_SUCCESS){// SMSS 在 5 秒内退出了 → 错误 → BUGCHECKKeBugCheck(SESSION5_INITIALIZATION_FAILED);}// SMSS 正常运行中 → 关闭句柄、释放内存ZwClose(ProcessInfo-ThreadHandle);ZwClose(ProcessInfo-ProcessHandle);ExpInitializationPhase;ExFreePoolWithTag(InitBuffer,TAG_INIT);等待 SMSS 进程句柄超时 5 秒如果 SMSS 在 5 秒内终止STATUS_SUCCESS → 蓝屏SESSION5_INITIALIZATION_FAILED如果 SMSS 正常运行STATUS_TIMEOUT → 清理并返回4.14 MmZeroPageThread (L2063)MmZeroPageThread();Phase1Initialization返回后立即调用此函数。零页线程是一个内核系统线程负责在后台清零空闲物理页面为后续的内存分配做准备。此函数永不返回。MmZeroPageThread() └─ while(TRUE) { KeWaitForSingleObject(ZeroPageEvent, ...); // 找到空闲页并清零 MmZeroPage(...); }5. 调用链总结KeSetPriorityThread(InitThread, 0) [KiInitializeKernel 末尾] → 调度器上下文切换 → Phase1Initialization(LoaderBlock) 开始运行 └─ Phase1InitializationDiscard(LoaderBlock) │ ├─ [1] HalInitSystem(1, LoaderBlock) HAL Phase 1 ├─ [2] 启动视频 Logo/横幅 ├─ [3] PoInitSystem(0) 电源 Phase 0 ├─ [4] 系统时间 时区 ├─ [5] KeStartAllProcessors() (SMP) AP 处理器启动 ├─ [6] 执行体 Phase 1 (Ob, Ex, Ke, Kd, Se, Mm, Cc, Cm, ...) ├─ [7] ★ IoInitSystem(LoaderBlock) ★ I/O 管理器 启动驱动 ├─ [8] 安全模式/WinPE 注册 ├─ [9] PoInitSystem(1) 电源 Phase 1 ├─ [10] PsInitSystem(LoaderBlock) 进程管理器 Phase 1 ├─ [11] MmFreeLoaderBlock(LoaderBlock) 释放引导加载程序 ├─ [12] ★ ExpLoadInitialProcess() ★ 启动 SMSS.EXE ├─ [13] ZwWaitForSingleObject(SMSS, 5s) 等待 SMSS └─ [返回] └─ MmZeroPageThread() 零页线程 (永不返回)6. SMSS 启动后的后续初始化当 SMSS (Session Manager Subsystem) 获得 CPU 控制权它执行以下操作smss.exe ├─ 初始化注册表 (加载更多配置单元) ├─ 创建系统环境变量 ├─ 启动 \SystemRoot\System32\csrss.exe (Windows 子系统) ├─ 启动 \SystemRoot\System32\winlogon.exe (登录管理器) │ └─ winlogon.exe │ ├─ 启动 \SystemRoot\System32\services.exe (服务管理器) │ ├─ 启动 \SystemRoot\System32\lsass.exe (安全认证) │ └─ 显示登录界面 │ ├─ 一旦成功后smss.exe 进入等待状态 └─ (WinLogon 继续初始化 → 桌面 → 用户登录)7. 设计要点7.1 Phase 0/1 的分段设计特性Phase 0 (空闲线程)Phase 1 (Phase1Initialization 线程)运行上下文空闲/引导线程真正的系统线程可以等待 I/O✗✓HAL 级别HAL Phase 0 (轻量)HAL Phase 1 (完整)I/O 系统IoInitSystemPreDriversIoInitSystem (全功能)可中断不可 (HIGH_PRIORITY)可 (但有最高优先级)显示无启动 Logo 进度条7.2 加载驱动是 Phase 1 的关键IoInitSystem是唯一能加载功能驱动的地方因为它需要完整的 I/O 管理器数据结构可等待的事件/同步对象分页池和非分页池已就绪注册表已可查询 (CmInitSystem1 已完成)7.3 SMSS 作为第一个用户模式进程SMSS 被选为第一个用户模式进程是因为它是 Windows 子系统的会话管理器它负责创建 CSRSS (Client-Server Runtime Subsystem)CSRSS 提供了 Win32 子系统 API只有在 Win32 就绪后其他 Windows 程序才能运行7.4 5 秒超时的意义ZwWaitForSingleObject(SMSS, 5s)的超时设计确保了如果 SMSS 立即崩溃映像损坏、配置错误5 秒内终止 →SESSSION5_INITIALIZATION_FAILED蓝屏如果 SMSS 正常运行它会保持存活 → 超时触发内核继续关闭句柄并清理7.5 释放 LoaderBlock 的时机在整个初始化链中最晚释放 LoaderBlock 的原因Phase 0 (KiInitializeKernel → ExpInitializeExecutive) — 需要 LoaderBlock 获取内存映射、注册表基址Phase 1 前半段 — 需要 LoaderBlock 获取启动选项、启动驱动列表、NLS 数据直到 PsInitSystem Phase 1 完成之后— 内核已经完全自给自足不再需要引导加载程序的任何数据