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)
c
VOID
NTAPI
Phase1Initialization(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)
c
InitBuffer = ExAllocatePoolWithTag(NonPagedPool, sizeof(INIT_BUFFER), TAG_INIT);
ExpInitializationPhase = 1;
KeSetPriorityThread(KeGetCurrentThread(), HIGH_PRIORITY);
- 分配
INIT_BUFFER(版本缓冲区、调试缓冲区、进程信息等的容器) - 将全局 Phase 标志设为 1
- 将当前线程优先级提升到最高,确保初始化不被其他线程打断
4.1 HAL Phase 1 (L1391)
c
if (!HalInitSystem(1, LoaderBlock)) KeBugCheck(HAL1_INITIALIZATION_FAILED);
HAL Phase 1 的完整初始化,与 Phase 0 的轻量初始化不同:
- 初始化完整的中断控制器 (PIC/APIC/IOAPIC)
- 时钟定时器校准和配置
- DMA 控制器初始化
- HAL 特定的资源报告
4.2 启动视频和显示 (L1393-L1428)
c
NoGuiBoot = (CommandLine && strstr(CommandLine, "NOGUIBOOT"));
SosEnabled = (CommandLine && strstr(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 启动 Logo
- SOS 模式:在 Logo 上叠加显示模块加载信息
- NOGUIBOOT 模式:释放显示所有权
WinPE (LiveCD) 检测 --- MININT 选项设置 InitIsWinPEMode = TRUE
4.3 启动横幅 (L1431-L1517)
- 从内核的 PE 消息资源中查找
WINDOWS_NT_BANNER消息条目 - 构建版本字符串:
KERNEL_VERSION_STR + NtBuildLab + 版本号 + CSDVersion InbvDisplayString()在屏幕上打印
4.4 系统时间初始化 (L1519-L1567)
c
PoInitSystem(0); // 电源 Phase 0
if (ExCmosClockIsSane && HalQueryRealTimeClock(&TimeFields))
{
if (Y2KHackRequired) TimeFields.Year = (CSHORT)YearHack;
RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
// ... 时区计算 ...
KeSetSystemTime(&UniversalBootTime, &OldTime, FALSE, NULL);
KeBootTime = UniversalBootTime;
}
- 通过 HAL 读取 CMOS/RTC 时间
- Y2K Hack : 如果启动参数包含
YEAR=XXXX,覆盖读取的年份(处理 BIOS Y2K Bug) - 根据时区偏差计算本地时间 → 设置系统时间
- 记录
KeBootTime供后续使用
4.5 AP 处理器启动 (L1569-L1603) 仅 SMP
c
// 解析 NUMPROC/BOOTPROC/MAXPROC
KeStartAllProcessors(); // 唤醒 AP
if (!HalAllProcessorsStarted()) KeBugCheck(...);
在多处理器系统中,在此处唤醒所有应用处理器 (AP) 。KeStartAllProcessors 发送 IPI 中断,使所有 AP 从 KiSystemStartup 的 AppCpuInit 自旋等待中释放,进入各自的 KiSystemStartupBootStack 初始化路径。
处理器限制选项:
| 选项 | 含义 |
|---|---|
NUMPROC=N |
最大逻辑处理器数(运行时可动态增加) |
BOOTPROC=N |
启动时最大处理器数 |
MAXPROC |
报告系统支持的处理器上限 |
4.6 处理器和内存信息显示 (L1605-L1655)
N System Processor [M MiB Memory]
- 构建字符串并用
InbvDisplayString显示 - 单处理器显示单数,多处理器显示复数
- 物理内存大小向上取整到 MiB
4.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_FAILED |
PnP 管理器 Phase 1 |
LpcInitSystem() |
LPC_INITIALIZATION_FAILED |
LPC (本地过程调用) |
XIPInit() |
--- | XIP (eXecute-In-Place) 支持 |
4.8 ★ IoInitSystem --- I/O 管理器 (L1849)
c
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)
└── 初始化文件系统识别
启动驱动的加载顺序由 CmpSortDriverList + CmpResolveDriverDependencies 在 WinLDR 阶段确定,按组 (Group) 和标签 (Tag) 排序。
4.9 安全模式和 WinPE 注册 (L1855-L1976)
安全模式 : 在 HKLM\...\Control\SafeBoot 下创建 Option 键,写入 OptionValue (1=MINIMAL, 2=NETWORK, 3=DSREPAIR) 和可选的 UseAlternateShell。
WinPE 模式 : 在 HKLM\...\Control 下创建 MiniNT 键,标记系统运行在 MiniNT 环境中。
4.10 电源 Phase 1 和进程管理器 Phase 1 (L1978-L1996)
c
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)
c
if (LoaderBlock == KeLoaderBlock) KeLoaderBlock = NULL;
MmFreeLoaderBlock(LoaderBlock);
释放所有引导加载程序分配的内存。自此以后,系统不再依赖 FreeLDR 提供的任何数据和结构------内核已经完全独立。
4.12 ★ ExpLoadInitialProcess --- 启动 SMSS (L2015-L2017)
c
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. 返回 Phase1InitializationDiscard
4.13 等待 SMSS 和清理 (L2019-L2053)
c
// 等待 5 秒让 SMSS 初始化
Timeout.QuadPart = Int32x32To64(5, -10000000); // 5 秒
Status = ZwWaitForSingleObject(ProcessInfo->ProcessHandle, FALSE, &Timeout);
if (Status == STATUS_SUCCESS)
{
// SMSS 在 5 秒内退出了 → 错误 → BUGCHECK
KeBugCheck(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)
c
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 系统 | IoInitSystemPreDrivers | IoInitSystem (全功能) |
| 可中断 | 不可 (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 完成之后 --- 内核已经完全自给自足,不再需要引导加载程序的任何数据