ReactOS bootcd.iso 引导到桌面显示过程分析
概述
ReactOS bootcd.iso 的启动过程是一个多阶段的复杂流程,涉及从硬件初始化到用户桌面显示的各个环节。整个过程可以分为以下六个主要阶段:
- BIOS/UEFI 阶段
- FreeLoader 引导加载器阶段
- WinLdr Windows兼容加载器阶段
- 内核初始化阶段
- 会话管理器(SMSS)阶段
- Winlogon与桌面显示阶段
阶段一:BIOS/UEFI 阶段
1.1 硬件自检 (POST)
当计算机启动时,BIOS 或 UEFI 固件首先执行加电自检(POST):
- 检查CPU、内存、主板等核心硬件
- 初始化基本硬件组件
- 检测并初始化显卡、存储设备等
1.2 引导设备选择
BIOS/UEFI 根据启动顺序查找可引导设备:
- 从 CD/DVD 驱动器读取 bootcd.iso
- 定位 ISO 镜像中的引导扇区或 EFI 引导文件
- 将引导加载器加载到内存并执行
关键文件 :ISO 镜像根目录下的 bootloader(如 bootmgr 或 freeldr)
阶段二:FreeLoader 引导加载器阶段
2.1 FreeLoader 入口
FreeLoader 是 ReactOS 的第一阶段引导加载器,入口点为 BootMain:
代码位置:freeldr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/freeldr.c#L92)
c
VOID __cdecl BootMain(IN PCCH CmdLine)
{
/* 加载命令行参数中的默认设置 */
LoadSettings(CmdLine);
/* 调试器预初始化 */
DebugInit(BootMgrInfo.DebugString);
/* 机器初始化 */
MachInit(CmdLine);
/* 检查CPU兼容性 */
FrLdrCheckCpuCompatibility();
/* UI预初始化 */
UiInitialize(FALSE);
/* 初始化内存管理器 */
MmInitializeMemoryManager();
/* 初始化I/O子系统 */
FsInit();
/* 初始化模块列表 */
PeLdrInitializeModuleList();
/* 检测启动设备 */
MachInitializeBootDevices();
/* 启动第二阶段加载器 */
LaunchSecondStageLoader();
}
2.2 第二阶段加载器 (rosload.exe)
LaunchSecondStageLoader 函数负责加载第二阶段引导加载器:
代码位置:freeldr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/freeldr.c#L69)
c
static ULONG LaunchSecondStageLoader(VOID)
{
/* 尝试从多个路径加载 rosload.exe */
if (!LoadRosload("rosload.exe", &ImageBase, &RosloadDTE))
{
if (!LoadRosload("loader\\rosload.exe", &ImageBase, &RosloadDTE))
{
return ENOENT;
}
}
/* 调用入口点 */
EntryPoint = VaToPa(RosloadDTE->EntryPoint);
(*EntryPoint)();
return ESUCCESS;
}
2.3 启动菜单显示
第二阶段加载器启动后,进入 RunLoader 函数,显示启动菜单:
代码位置:bootmgr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/bootmgr.c#L386)
c
VOID RunLoader(VOID)
{
/* 加载额外的SCSI驱动 */
LoadBootDeviceDriver();
/* 打开 FREELDR.INI 并加载全局设置 */
IniFileInitialize();
LoadSettings(NULL);
/* 调试器初始化 */
DebugInit(GetBootMgrInfo()->DebugString);
/* UI初始化 */
UiInitialize(TRUE);
/* 获取操作系统列表 */
OperatingSystemList = InitOperatingSystemList(&OperatingSystemCount,
&SelectedOperatingSystem);
/* 显示启动菜单 */
for (;;)
{
UiDisplayMenu("Please select the operating system to start:",
"...",
OperatingSystemDisplayNames,
OperatingSystemCount,
SelectedOperatingSystem,
GetBootMgrInfo()->TimeOut,
&SelectedOperatingSystem,
FALSE,
MainBootMenuKeyPressFilter,
OperatingSystemList);
/* 加载选择的操作系统 */
LoadOperatingSystem(&OperatingSystemList[SelectedOperatingSystem]);
}
}
2.4 操作系统加载
用户选择操作系统后,LoadOperatingSystem 根据 BootType 选择对应的加载方法:
代码位置:bootmgr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/bootmgr.c#L286)
c
VOID LoadOperatingSystem(_In_ OperatingSystemItem* OperatingSystem)
{
/* 获取操作系统加载方法 */
OSLoadingMethod = GetOSLoadingMethod(SectionId);
/* 构建ARC兼容的参数向量 */
Argv = BuildArgvForOsLoader(OperatingSystem->LoadIdentifier, SectionId, &Argc);
/* 安装驱动器映射 */
DriveMapMapDrivesInSection(SectionId);
/* 启动OS加载器 */
OSLoadingMethod->OsLoader(Argc, Argv, NULL);
}
对于 ReactOS,BootType 为 "Windows" 或 "Windows2003",对应的加载器为 LoadAndBootWindows。
阶段三:WinLdr Windows兼容加载器阶段
3.1 LoadAndBootWindows 入口
WinLdr 是 Windows NT 兼容的加载器,负责加载内核和相关组件:
代码位置:winldr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/ntldr/winldr.c#L1178)
c
ARC_STATUS LoadAndBootWindows(IN ULONG Argc, IN PCHAR Argv[], IN PCHAR Envp[])
{
/* 获取BootType并转换为OS版本 */
/* 获取系统分区路径 */
/* 获取启动路径和选项 */
/* 加载系统注册表 hive */
WinLdrInitSystemHive(LoaderBlock, BootPath, FALSE);
/* 扫描系统 hive,加载NLS数据和引导驱动列表 */
WinLdrScanSystemHive(LoaderBlock, BootPath);
/* 调用通用加载函数 */
return LoadAndBootWindowsCommon(...);
}
3.2 核心组件加载
LoadWindowsCore 函数负责加载 NT 核心文件:
代码位置:winldr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/ntldr/winldr.c#L737)
c
BOOLEAN LoadWindowsCore(...)
{
/* 加载内核文件 ntoskrnl.exe */
KernelBase = LoadModule(&LoaderBlock->LoadOrderListHead,
DirPath, KernelFileName,
"ntoskrnl.exe", LoaderSystemCode,
KernelDTE, 30);
/* 加载HAL文件 hal.dll */
HalBase = LoadModule(&LoaderBlock->LoadOrderListHead,
DirPath, HalFileName,
"hal.dll", LoaderHalCode,
&HalDTE, 35);
/* 加载内核调试传输DLL kdcom.dll */
KdDllBase = LoadModule(&LoaderBlock->LoadOrderListHead,
DirPath, KdDllName,
"kdcom.dll", LoaderSystemCode,
&KdDllDTE, 40);
/* 加载启动视频驱动 bootvid.dll */
BootVidBase = LoadModule(&LoaderBlock->LoadOrderListHead,
DirPath, BootVidName,
"bootvid.dll", LoaderSystemCode,
&BootVidDTE, 45);
/* 扫描所有模块的导入表,加载依赖 */
PeLdrScanImportDescriptorTable(...);
}
3.3 引导驱动加载
代码位置:winldr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/ntldr/winldr.c#L388)
c
BOOLEAN WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock, PCSTR BootPath)
{
/* 遍历引导驱动列表 */
NextBd = LoaderBlock->BootDriverListHead.Flink;
while (NextBd != &LoaderBlock->BootDriverListHead)
{
/* 加载每个驱动 */
WinLdrLoadDeviceDriver(&LoaderBlock->LoadOrderListHead,
BootPath,
&BootDriver->FilePath,
0,
&BootDriver->LdrEntry);
NextBd = BootDriver->Link.Flink;
}
}
3.4 初始化阶段一
代码位置:winldr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/ntldr/winldr.c#L125)
c
static VOID WinLdrInitializePhase1(...)
{
/* 设置ArcBootDeviceName */
/* 设置ArcHalDeviceName */
/* 设置SystemRoot */
/* 设置LoadOptions */
/* 转换所有列表到虚拟地址 */
/* 加载驱动数据库 */
}
3.5 进入内核模式
代码位置:winldr.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/ntldr/winldr.c#L1376)
c
ARC_STATUS LoadAndBootWindowsCommon(...)
{
/* 硬件检测 */
LoaderBlock->ConfigurationRoot = MachHwDetect(BootOptions);
/* 加载核心组件 */
LoadWindowsCore(...);
/* 加载引导驱动 */
WinLdrLoadBootDrivers(LoaderBlock, BootPath);
/* 阶段一初始化 */
WinLdrInitializePhase1(...);
/* 切换到分页模式 */
WinLdrSetupMemoryLayout(LoaderBlock);
WinLdrSetProcessorContext(OperatingSystemVersion);
/* 获取内核入口点 */
KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
/* 传递控制权给内核 */
(*KiSystemStartup)(LoaderBlockVA);
}
阶段四:内核初始化阶段
4.1 KiSystemStartup - 内核入口点
代码位置:kiinit.c(file:///d:/my2024/reactos/ntoskrnl/ke/i386/kiinit.c#L737)
c
VOID NTAPI KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
/* 保存LoaderBlock指针 */
KeLoaderBlock = LoaderBlock;
/* 初始化机器类型 */
KiInitializeMachineType();
/* 获取GDT、IDT、PCR和TSS指针 */
KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss);
/* 初始化PCR */
RtlZeroMemory(Pcr, PAGE_SIZE);
KiInitializePcr(Cpu, Pcr, Idt, Gdt, Tss, InitialThread, (PVOID)KiDoubleFaultStack);
/* 设置IDT */
KeInitExceptions();
/* 验证CPU功能 */
KiVerifyCpuFeatures(Pcr->Prcb);
/* HAL初始化处理器 */
HalInitializeProcessor(Cpu, KeLoaderBlock);
/* 切换到新的内核堆栈 */
KiSwitchToBootStack(InitialStack & ~3);
}
4.2 KiSystemStartupBootStack - 在新堆栈上初始化
代码位置:kiinit.c(file:///d:/my2024/reactos/ntoskrnl/ke/i386/kiinit.c#L685)
c
VOID NTAPI KiSystemStartupBootStack(VOID)
{
/* 初始化内核 */
KiInitializeKernel(&KiInitialProcess.Pcb,
(PKTHREAD)KeLoaderBlock->Thread,
(PVOID)(KeLoaderBlock->KernelStack & ~3),
(PKPRCB)__readfsdword(KPCR_PRCB),
KeNumberProcessors - 1,
KeLoaderBlock);
/* 设置线程优先级为0 */
Thread->Priority = 0;
/* 启用中断 */
_enable();
KeLowerIrql(DISPATCH_LEVEL);
/* 进入空闲循环 */
KiIdleLoop();
}
4.3 KiInitializeKernel - 内核核心初始化
代码位置:kiinit.c(file:///d:/my2024/reactos/ntoskrnl/ke/i386/kiinit.c#L430)
c
VOID NTAPI KiInitializeKernel(...)
{
/* 初始化电源管理 */
PoInitializePrcb(Prcb);
/* 设置NX策略 */
SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
/* 保存CPU状态 */
KiSaveProcessorControlState(&Prcb->ProcessorState);
/* 初始化自旋锁和DPC数据 */
KiInitSpinLocks(Prcb, Number);
/* 对于引导CPU,初始化更多组件 */
if (!Number)
{
/* 设置引导级标志 */
KeI386CpuType = Prcb->CpuType;
/* 初始化内核可移植部分 */
KiInitSystem();
/* 初始化空闲进程和进程列表 */
KeInitializeProcess(InitProcess, ...);
}
/* 初始化Executive */
ExpInitializeExecutive(Number, LoaderBlock);
/* 设置线程优先级为0,进入Phase 1 */
KeSetPriorityThread(InitThread, 0);
}
4.4 ExpInitializeExecutive - 执行层初始化
代码位置:init.c(file:///d:/my2024/reactos/ntoskrnl/ex/init.c#L928)
c
VOID NTAPI ExpInitializeExecutive(IN ULONG Cpu, IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
/* 验证Loader版本 */
if (!ExpIsLoaderValid(LoaderBlock))
KeBugCheckEx(MISMATCHED_HAL, ...);
/* 对于应用CPU,只初始化HAL */
if (Cpu)
{
HalInitSystem(ExpInitializationPhase, LoaderBlock);
return;
}
/* 设置阶段为0 */
ExpInitializationPhase = 0;
/* 初始化NLS表 */
RtlInitNlsTables(...);
/* HAL初始化 */
HalInitSystem(0, LoaderBlock);
/* 启用中断 */
_enable();
/* 初始化Executive阶段0 */
ExInitSystem();
/* 初始化内存管理器阶段0 */
MmArmInitSystem(0, LoaderBlock);
/* 加载引导符号 */
ExpLoadBootSymbols(LoaderBlock);
/* 初始化对象管理器 */
ObInitSystem();
/* 初始化安全管理器 */
SeInitSystem();
/* 初始化进程管理器 */
PsInitSystem(LoaderBlock);
/* 初始化即插即用管理器 */
PpInitSystem();
}
4.5 Phase1Initialization - 阶段1初始化
代码位置:init.c(file:///d:/my2024/reactos/ntoskrnl/ex/init.c#L1351)
Phase1InitializationDiscard 是核心的阶段1初始化函数,执行以下操作:
| 进度 | 操作 |
|---|---|
| 0-5% | HAL阶段1初始化、显示版本信息、启动应用CPU |
| 5-10% | 对象管理器、执行层、内核、调试器、安全管理器初始化 |
| 10-15% | 创建SystemRoot链接、内存管理器阶段1、NLS段、缓存管理器、注册表初始化 |
| 15-20% | 文件系统运行时库、PnP管理器阶段1、LPC初始化 |
| 20-75% | I/O子系统初始化 |
| 75-90% | VDM支持、电源管理阶段1、进程管理器阶段1 |
| 90-100% | 清理LoaderBlock、启动初始进程(SMSS) |
关键代码片段:
c
/* 显示启动logo */
InbvEnableBootDriver(!NoGuiBoot);
InbvDriverInitialize(LoaderBlock, IDB_MAX_RESOURCES);
DisplayBootBitmap(SosEnabled);
/* 初始化I/O子系统 */
IoInitSystem(LoaderBlock);
/* 启动初始进程 SMSS */
ExpLoadInitialProcess(InitBuffer, &ProcessParameters, &Environment);
/* 等待SMSS初始化完成 */
Status = ZwWaitForSingleObject(ProcessInfo->ProcessHandle, FALSE, &Timeout);
4.6 ExpLoadInitialProcess - 创建SMSS进程
代码位置:init.c(file:///d:/my2024/reactos/ntoskrnl/ex/init.c#L389)
c
VOID NTAPI ExpLoadInitialProcess(...)
{
/* 分配进程参数内存 */
ZwAllocateVirtualMemory(NtCurrentProcess(), &ProcessParams, ...);
/* 设置进程参数 */
ProcessParams->CurrentDirectory.DosPath = NtSystemRoot;
ProcessParams->DllPath = NtSystemRoot + "\\System32";
ProcessParams->ImagePathName = "\\SystemRoot\\System32\\smss.exe";
/* 创建SMSS进程 */
Status = RtlCreateUserProcess(&SmssName, ...);
/* 恢复线程执行 */
ZwResumeThread(ProcessInformation->ThreadHandle, NULL);
}
阶段五:会话管理器(SMSS)阶段
5.1 SMSS 主函数
代码位置:smss.c(file:///d:/my2024/reactos/base/system/smss/smss.c#L430)
c
NTSTATUS __cdecl _main(IN INT argc, IN PCHAR argv[], IN PCHAR envp[], IN ULONG DebugFlag)
{
/* 设置为关键进程 */
RtlSetProcessIsCritical(TRUE, NULL, FALSE);
RtlSetThreadIsCritical(TRUE, NULL, FALSE);
/* 提升优先级 */
SetBasePriority = 11;
NtSetInformationProcess(NtCurrentProcess(), ProcessBasePriority, ...);
/* 初始化SMSS */
Status = SmpInit(&InitialCommand, &Handles[0]);
/* 执行初始命令(Winlogon.exe) */
Status = SmpExecuteInitialCommand(0, &InitialCommand, &Handles[1], NULL);
/* 等待CSRSS或Winlogon终止 */
Status = NtWaitForMultipleObjects(RTL_NUMBER_OF(Handles), Handles, WaitAny, ...);
}
5.2 SmpInit - SMSS初始化
SmpInit 函数负责:
- 创建SM API端口
- 创建会话0
- 加载子系统(CSRSS)
- 设置初始命令(Winlogon)
5.3 SmpExecuteInitialCommand - 执行初始命令
代码位置:smss.c(file:///d:/my2024/reactos/base/system/smss/smss.c#L282)
c
NTSTATUS NTAPI SmpExecuteInitialCommand(...)
{
/* 解析初始命令行 */
SmpParseCommandLine(InitialCommand, &Flags, &FileName, &Directory, &Arguments);
/* 执行初始命令(Winlogon),延迟执行 */
Status = SmpExecuteImage(&FileName, &Directory, InitialCommand,
MuSessionId, SMP_DEFERRED_FLAG, &ProcessInfo);
/* 完成进程初始化 */
Status = SmExecPgm(SmApiPort, &ProcessInfo, FALSE);
}
阶段六:Winlogon与桌面显示阶段
6.1 Winlogon 启动
Winlogon 是 Windows 登录管理器,负责用户身份验证、加载用户配置文件和启动桌面会话。
代码位置:winlogon.c(file:///d:/my2024/reactos/base/system/winlogon/winlogon.c#L431)
c
int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance,
IN LPSTR lpCmdLine, IN int nShowCmd)
{
/* 将自己标记为关键进程 */
RtlSetProcessIsCritical(TRUE, NULL, FALSE);
RtlSetThreadIsCritical(TRUE, NULL, FALSE);
/* 更新注册表中的TCP/IP缓存信息 */
UpdateTcpIpInformation();
/* 注册登录进程 */
RegisterLogonProcess(GetCurrentProcessId(), TRUE);
/* 创建窗口站和桌面 */
CreateWindowStationAndDesktops(WLSession);
/* 锁定工作站 */
LockWorkstation(WLSession);
/* 加载默认键盘布局 */
InitKeyboardLayouts();
/* 启动RPC服务器 */
StartRpcServer();
/* 启动服务管理器 services.exe */
StartServicesManager();
/* 启动本地安全权威子系统 lsass.exe */
StartLsass();
/* 等待LSA服务器就绪 */
WaitForLsass();
/* 初始化通知 */
InitNotifications();
/* 加载并初始化GINA */
GinaInit(WLSession);
/* 显示启动状态消息 */
DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
/* 创建SAS窗口处理安全注意序列 */
InitializeSAS(WLSession);
/* 发送Ctrl+Alt+Del消息 */
PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0);
/* 消息循环 */
while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
}
Winlogon 初始化流程:
| 步骤 | 操作 | 关键函数 |
|---|---|---|
| 1 | 标记为关键进程 | RtlSetProcessIsCritical |
| 2 | 更新TCP/IP注册表信息 | UpdateTcpIpInformation |
| 3 | 注册登录进程 | RegisterLogonProcess |
| 4 | 创建窗口站和桌面 | CreateWindowStationAndDesktops |
| 5 | 加载键盘布局 | InitKeyboardLayouts |
| 6 | 启动RPC服务器 | StartRpcServer |
| 7 | 启动services.exe | StartServicesManager |
| 8 | 启动lsass.exe | StartLsass |
| 9 | 等待LSA就绪 | WaitForLsass |
| 10 | 初始化GINA | GinaInit |
| 11 | 进入消息循环 | GetMessageW |
6.2 CSRSS 初始化
CSRSS(Client/Server Runtime Subsystem) 是 Win32 子系统的核心,管理 Windows 应用程序、处理窗口消息和管理控制台窗口。
代码位置:csrss.c(file:///d:/my2024/reactos/subsystems/csr/csrss/csrss.c#L37)
c
int _cdecl _main(int argc, char *argv[], char *envp[], int DebugFlag)
{
/* 设置进程基础优先级 */
NtSetInformationProcess(NtCurrentProcess(), ProcessBasePriority,
&BasePriority, sizeof(BasePriority));
/* x86平台提升IOPL权限以访问VGA寄存器 */
NtSetInformationProcess(NtCurrentProcess(), ProcessUserModeIOPL, NULL, 0);
/* 通过CSRSRV初始化CSR */
Status = CsrServerInitialization(argc, argv);
/* 禁用硬错误 */
CsrpSetDefaultProcessHardErrorMode();
/* 如果是会话0,标记为关键进程 */
if (NtCurrentPeb()->SessionId == 0)
RtlSetProcessIsCritical(TRUE, NULL, FALSE);
/* 终止当前线程,CSRSRV保持运行 */
NtTerminateThread(NtCurrentThread(), Status);
}
CSRSS 初始化流程:
| 步骤 | 操作 | 目的 |
|---|---|---|
| 1 | 设置优先级 | 提升到高于普通进程 |
| 2 | 提升IOPL | x86平台访问VGA硬件 |
| 3 | CSR初始化 | 通过CSRSRV创建子系统环境 |
| 4 | 禁用硬错误 | 防止子系统崩溃时弹出错误 |
| 5 | 标记关键进程 | 会话0中的CSRSS崩溃会导致系统重启 |
6.3 桌面创建
代码位置:desktop.c(file:///d:/my2024/reactos/win32ss/user/ntuser/desktop.c)
桌面对象创建流程:
- 创建窗口站(Window Station) :
CreateWindowStationAndDesktops创建WinSta0窗口站 - 创建桌面(Desktop) :创建
Winlogon桌面和Default桌面 - 启动资源管理器(Explorer):登录成功后启动 shell
- 加载桌面背景和图标:Explorer 负责桌面界面渲染
6.4 用户登录
Winlogon 通过 GINA(Graphical Identification and Authentication) 显示登录界面:
| 步骤 | 操作 | 组件 |
|---|---|---|
| 1 | 显示登录界面 | MSGINA |
| 2 | 接受用户名和密码 | Winlogon + GINA |
| 3 | 验证用户身份 | LSASS |
| 4 | 加载用户注册表配置 | Winlogon |
| 5 | 启动用户进程 | Explorer.exe |
| 6 | 切换到用户桌面 | Win32k.sys |
6.5 服务启动
Winlogon 启动的关键服务:
services.exe - 服务控制管理器:
c
static BOOL StartServicesManager(VOID)
{
res = CreateProcessW(L"services.exe", NULL, NULL, NULL, FALSE,
DETACHED_PROCESS, NULL, NULL, &StartupInfo, &ProcessInformation);
}
lsass.exe - 本地安全权威子系统:
c
static BOOL StartLsass(VOID)
{
res = CreateProcessW(L"lsass.exe", NULL, NULL, NULL, FALSE,
DETACHED_PROCESS, NULL, NULL, &StartupInfo, &ProcessInformation);
}
Winlogon 通过事件 LSA_RPC_SERVER_ACTIVE 等待 LSASS 就绪。
完整流程时序图
BIOS/UEFI
│
▼
FreeLoader (bootmgr.c)
│── BootMain()
│ ├── LoadSettings()
│ ├── MachInit()
│ ├── UiInitialize()
│ ├── MmInitializeMemoryManager()
│ ├── FsInit()
│ └── LaunchSecondStageLoader()
│
▼
FreeLoader (rosload.exe)
│── RunLoader()
│ ├── IniFileInitialize()
│ ├── UiDisplayMenu()
│ └── LoadOperatingSystem()
│ └── LoadAndBootWindows()
│
▼
WinLdr (winldr.c)
│── LoadAndBootWindows()
│ ├── WinLdrInitSystemHive()
│ ├── WinLdrScanSystemHive()
│ └── LoadAndBootWindowsCommon()
│ ├── MachHwDetect()
│ ├── LoadWindowsCore()
│ │ ├── ntoskrnl.exe
│ │ ├── hal.dll
│ │ ├── kdcom.dll
│ │ └── bootvid.dll
│ ├── WinLdrLoadBootDrivers()
│ ├── WinLdrInitializePhase1()
│ ├── WinLdrSetupMemoryLayout()
│ └── KiSystemStartup()
│
▼
Kernel (kiinit.c)
│── KiSystemStartup()
│ ├── KiInitializeMachineType()
│ ├── KiInitializePcr()
│ ├── KiVerifyCpuFeatures()
│ └── KiSwitchToBootStack()
│
▼
│── KiSystemStartupBootStack()
│ ├── KiInitializeKernel()
│ │ ├── PoInitializePrcb()
│ │ ├── KiInitSpinLocks()
│ │ ├── KiInitSystem()
│ │ └── ExpInitializeExecutive()
│ └── KiIdleLoop()
│
▼
Executive (init.c)
│── Phase1Initialization()
│ ├── Phase1InitializationDiscard()
│ │ ├── HAL初始化
│ │ ├── 对象管理器初始化
│ │ ├── 内存管理器初始化
│ │ ├── I/O子系统初始化
│ │ ├── 注册表初始化
│ │ └── ExpLoadInitialProcess()
│ └── MmZeroPageThread()
│
▼
SMSS (smss.c)
│── _main()
│ ├── SmpInit()
│ │ ├── 创建SM API端口
│ │ ├── 创建会话0
│ │ └── 加载CSRSS
│ └── SmpExecuteInitialCommand()
│ └── 启动Winlogon
│
▼
Winlogon + CSRSS
│── 显示登录界面
│── 用户身份验证
│── 加载用户配置
│── 启动资源管理器
│
▼
桌面显示
关键数据结构
LOADER_PARAMETER_BLOCK
定义位置:Windows NT 兼容结构
c
typedef struct _LOADER_PARAMETER_BLOCK {
ULONG Size;
ULONG Revision;
PLOADER_PARAMETER_EXTENSION Extension;
PUNICODE_STRING ArcBootDeviceName;
PUNICODE_STRING ArcHalDeviceName;
PUNICODE_STRING NtBootPathName;
PUNICODE_STRING NtHalPathName;
PCHAR LoadOptions;
ULONG LoadOptionsSize;
PLIST_ENTRY LoadOrderListHead;
PLIST_ENTRY MemoryDescriptorListHead;
PLIST_ENTRY BootDriverListHead;
PNLS_DATA_BLOCK NlsData;
PVOID RegistryBase;
// ... 其他字段
} LOADER_PARAMETER_BLOCK, *PLOADER_PARAMETER_BLOCK;
KPCR (Kernel Processor Control Region)
定义位置:kiinit.c(file:///d:/my2024/reactos/ntoskrnl/ke/i386/kiinit.c#L284)
每个处理器一个 KPCR,包含:
- 处理器状态信息
- 当前线程指针
- GDT/IDT/TSS 指针
- PRCB (Processor Control Block)
内存布局变化
引导阶段
| 内存区域 | 用途 |
|---|---|
| 0x00000000-0x0000FFFF | BIOS/视频内存 |
| 0x00010000-0x0008FFFF | FreeLoader 代码和数据 |
| 0x00090000-0x0009FFFF | 堆栈 |
| 0x000A0000-0x000FFFFF | 视频内存 |
| 0x00100000+ | 内核和驱动加载区域 |
内核模式
| 内存区域 | 用途 |
|---|---|
| 0x00000000-0x0000FFFF | 陷阱帧(只读) |
| 0x80000000-0xC0000000 | 内核代码和数据 |
| 0xC0000000-0xFFFFFFFF | 系统空间(分页) |
阶段七:ISO 特定启动细节
7.1 El Torito 引导目录
bootcd.iso 遵循 El Torito 规范,这是 CD-ROM 引导的标准:
El Torito 结构:
- 引导目录(Boot Catalog):位于扇区 17,包含引导条目
- 引导介质描述符:指定 CD 类型(1=CD-ROM)
- 初始加载程序(Initial Load Program):FreeLoader 引导扇区
BIOS 读取流程:
- BIOS 读取扇区 0-15:ISO 头部
- BIOS 读取扇区 16:主卷描述符(PVD)
- BIOS 读取扇区 17:El Torito 引导目录
- 根据引导目录定位引导加载器
7.2 ISO9660 文件系统支持
FreeLoader 内置了 ISO9660 文件系统驱动,用于从 CD-ROM 读取文件。
代码位置:iso.c(file:///d:/my2024/reactos/boot/freeldr/freeldr/lib/fs/iso.c#L602)
c
const DEVVTBL* IsoMount(ULONG DeviceId)
{
/* 读取ISO主卷描述符(PVD),位于扇区16 */
Position.QuadPart = 16 * SECTORSIZE;
Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
Status = ArcRead(DeviceId, Pvd, SECTORSIZE, &Count);
/* 验证PVD有效性 */
if (!(Pvd->VdType == 1 &&
RtlEqualMemory(Pvd->StandardId, "CD001", 5) &&
Pvd->VdVersion == 1))
{
WARN("Unrecognized CD-ROM format\n");
return NULL;
}
/* 验证逻辑块大小 */
if (Pvd->LogicalBlockSizeL != SECTORSIZE)
{
ERR("Unsupported LogicalBlockSize %u\n", Pvd->LogicalBlockSizeL);
return NULL;
}
/* 创建卷信息结构 */
Volume = FrLdrTempAlloc(sizeof(*Volume), TAG_ISO_VOLUME);
Volume->VolumeSizeLBN = Pvd->VolumeSpaceSizeL;
Volume->LogicalBlockSize = Pvd->LogicalBlockSizeL;
/* 缓存根目录信息 */
Volume->PvdDirectorySector = Pvd->RootDirRecord.ExtentLocationL;
Volume->PvdDirectoryLength = Pvd->RootDirRecord.DataLengthL;
IsoVolumes[DeviceId] = Volume;
/* 返回ISO9660函数表 */
return &Iso9660FuncTable;
}
ISO9660 文件系统操作:
| 函数 | 功能 |
|---|---|
IsoMount |
挂载ISO卷,读取主卷描述符 |
IsoOpen |
打开文件,查找文件位置 |
IsoRead |
读取文件内容,处理扇区对齐 |
IsoSeek |
文件指针定位 |
IsoClose |
关闭文件句柄 |
IsoGetFileInformation |
获取文件信息 |
7.3 文件查找流程
c
static ARC_STATUS IsoLookupFile(PCSTR FileName, ULONG DeviceId, PISO_FILE_INFO IsoFileInfo)
{
/* 提取文件名和目录路径 */
FileNameStr = IsoLastPathSeparator(FileName) + 1;
DirectoryPathLength = FileNameStr - FileName;
/* 检查目录是否已缓存 */
DoFullLookup = (DirectoryPathLength != Volume->DirectoryPathLength) ||
!RtlEqualMemory(FileName, Volume->DirectoryPath, DirectoryPathLength);
/* 逐层查找路径 */
for (i = 0; i < NumberOfPathParts; i++)
{
/* 读取目录内容到缓冲区 */
Status = IsoBufferDirectory(DeviceId, DirectorySector, DirectoryLength, &DirectoryBuffer);
/* 在目录缓冲区中搜索文件名 */
if (!IsoSearchDirectoryBufferForFile(DirectoryBuffer, DirectoryLength, PathPart, IsoFileInfo))
return ENOENT;
/* 保存目录缓冲区供后续使用 */
if ((i + 1) >= NumberOfPathParts)
{
Volume->DirectoryBuffer = DirectoryBuffer;
Volume->DirectoryLength = DirectoryLength;
RtlCopyMemory(Volume->DirectoryPath, FullPath, DirectoryPathLength);
}
}
return ESUCCESS;
}
7.4 CD 启动与硬盘启动的差异
| 特性 | CD 启动 | 硬盘启动 |
|---|---|---|
| 引导设备 | CD-ROM | 硬盘 |
| 文件系统 | ISO9660 | FAT/NTFS |
| 引导目录 | El Torito | MBR/VBR |
| 读取方式 | 扇区读取 | 文件系统驱动 |
| 可写性 | 只读 | 可读写 |
| 引导加载器位置 | ISO 镜像内 | 分区引导扇区 |
总结
ReactOS 的启动过程遵循 Windows NT 的经典引导架构,主要特点:
-
多阶段引导:BIOS → FreeLoader → WinLdr → Kernel → SMSS → Winlogon
-
模块化设计:
- FreeLoader 负责硬件检测和菜单显示
- WinLdr 负责内核和驱动加载
- 内核负责核心服务初始化
- SMSS 负责会话管理
- Winlogon 负责用户交互
-
兼容性考虑:
- WinLdr 完全兼容 Windows NT 加载器接口
- 支持 ARC 命名规范
- 支持标准 NT 启动选项(SOS, NOGUIBOOT, SAFEBOOT等)
-
安全机制:
- SMSS 和 Winlogon 标记为关键进程
- 进程优先级提升
- 异常处理和系统恢复机制
-
ISO 启动支持:
- 内置 ISO9660 文件系统驱动
- 支持 El Torito 引导规范
- 目录缓存优化读取性能