ReactOS bootcd.iso 引导到桌面显示过程分析

ReactOS bootcd.iso 引导到桌面显示过程分析

概述

ReactOS bootcd.iso 的启动过程是一个多阶段的复杂流程,涉及从硬件初始化到用户桌面显示的各个环节。整个过程可以分为以下六个主要阶段:

  1. BIOS/UEFI 阶段
  2. FreeLoader 引导加载器阶段
  3. WinLdr Windows兼容加载器阶段
  4. 内核初始化阶段
  5. 会话管理器(SMSS)阶段
  6. Winlogon与桌面显示阶段

阶段一:BIOS/UEFI 阶段

1.1 硬件自检 (POST)

当计算机启动时,BIOS 或 UEFI 固件首先执行加电自检(POST)

  • 检查CPU、内存、主板等核心硬件
  • 初始化基本硬件组件
  • 检测并初始化显卡、存储设备等

1.2 引导设备选择

BIOS/UEFI 根据启动顺序查找可引导设备:

  • 从 CD/DVD 驱动器读取 bootcd.iso
  • 定位 ISO 镜像中的引导扇区或 EFI 引导文件
  • 将引导加载器加载到内存并执行

关键文件 :ISO 镜像根目录下的 bootloader(如 bootmgrfreeldr


阶段二: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)

桌面对象创建流程:

  1. 创建窗口站(Window Station)CreateWindowStationAndDesktops 创建 WinSta0 窗口站
  2. 创建桌面(Desktop) :创建 Winlogon 桌面和 Default 桌面
  3. 启动资源管理器(Explorer):登录成功后启动 shell
  4. 加载桌面背景和图标: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 读取流程

  1. BIOS 读取扇区 0-15:ISO 头部
  2. BIOS 读取扇区 16:主卷描述符(PVD)
  3. BIOS 读取扇区 17:El Torito 引导目录
  4. 根据引导目录定位引导加载器

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 的经典引导架构,主要特点:

  1. 多阶段引导:BIOS → FreeLoader → WinLdr → Kernel → SMSS → Winlogon

  2. 模块化设计

    • FreeLoader 负责硬件检测和菜单显示
    • WinLdr 负责内核和驱动加载
    • 内核负责核心服务初始化
    • SMSS 负责会话管理
    • Winlogon 负责用户交互
  3. 兼容性考虑

    • WinLdr 完全兼容 Windows NT 加载器接口
    • 支持 ARC 命名规范
    • 支持标准 NT 启动选项(SOS, NOGUIBOOT, SAFEBOOT等)
  4. 安全机制

    • SMSS 和 Winlogon 标记为关键进程
    • 进程优先级提升
    • 异常处理和系统恢复机制
  5. ISO 启动支持

    • 内置 ISO9660 文件系统驱动
    • 支持 El Torito 引导规范
    • 目录缓存优化读取性能
相关推荐
caimouse7 小时前
ReactOS BootCD 光盘布局完整深度分析
单片机·reactos
caimouse10 小时前
KiSwitchToBootStack 函数分析
reactos
caimouse11 小时前
KiSystemStartupBootStack 函数分析
开发语言·reactos
caimouse3 天前
ReactOS Development Notes
reactos
爱学习的大牛1232 年前
通过VirtualBox虚拟机安装和调试编译好的 ReactOS
reactos·windows内核学习
zhyjhacker2 年前
ReactOS 4.2 OBJECT_TYPE_INITIALIZERj结构体的实现
c++·windows·reactos
zhyjhacker2 年前
3.1.1ReactOS系统中搜索给定长度的空间地址区间函数的实现
linux·c++·嵌入式硬件·reactos
zhyjhacker2 年前
memset()函数的实现
c++·windows·内核·reactos
zhyjhacker2 年前
3.1.1 ReactOS系统中二叉树创建一个MEMORY_AREA节点
java·前端·c++·windows·算法·内核·reactos