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 引导规范
    • 目录缓存优化读取性能
相关推荐
caimouse10 天前
TCP/IP 协议驱动 (tcpip.sys) 分析
网络协议·tcp/ip·reactos
caimouse12 天前
MM 学习笔记 09:进程会话与工作集
笔记·学习·reactos
caimouse12 天前
MM 学习笔记 10:页面文件与系统加载器
笔记·学习·reactos
caimouse13 天前
WINE IE 与 wine_gecko 架构分析
架构·reactos
caimouse17 天前
Chrome V49 (49.0.2623.112) 在 ReactOS 上运行所需的系统依赖
chrome·reactos
caimouse17 天前
Windows 内存管理概念详解
reactos
caimouse17 天前
MM 学习笔记 01:miarm.h 核心头文件分析
笔记·学习·reactos
caimouse17 天前
Chrome V49 SxS 加载问题分析与修复
chrome·reactos
caimouse17 天前
mm学习笔记_04:VAD树算法与地址空间分配
笔记·学习·算法·reactos
caimouse18 天前
WINLOGON 初始化与作用分析
reactos