Os loader 刚接获控制时,处理器虽然已经工作在保护模式下,但是它的虚拟地址转译机制尚未开启,所以,处理器仍然直接使用物理地址。Os loader 首先做的工作是把物理内存管起来,用一个内存描述符(memory descriptor)数组把每一段内存的大小和用途记录下来,然后构造页目录和页表,使得16 MB 以下的内存能够通过页面映射(paging)机制进行访问,再设置好页目录寄存器,并打开页面映射机制。之后,os loader 继续执行其他的初始化工作,包括I/O 设备的初始化等。如果它还需要调用BIOS 中的服务(比如中断13h、中断15h 等),则必须保护好保护模式下的设置,并暂时切换回到实模式,待服务完成以后再切换到保护模式,并恢复设置。
Windows 的引导选项可以用来指示当前这次引导的各种参数,包括内核模块的文件名称、HAL 的文件名称、CPU 参数、各种内存参数、调试参数,等等。关于这些引导选项的全面列表和介绍,可参考[MSDN-BOOT]。接下来os loader 加载并执行NTDETECT.COM 程序,这是一个16 位实模式程序,它利用系统的BIOS 来查询系统的基本设备和配置信息,包括系统的日期和时间、总线的类型、磁盘的信息、输入/输出的接口信息等。这些信息被收集起来,在引导过程的后期被存放到注册表HKLM\\HARDWARE\\DESCRIPTION 键的下面。
代码摘自\\ntos\\boot\\startup\\i386\\main.c VOID SuMain(
INFPVOIDBtRootDir, INFPDISKBPBBtBiosBlock, INSHORTBtBootDrive ) /*++
Routine Description:
Main entrypoint of the SU module. Control is passed from the boot sector to startup.asm which does some run-time fixups on the stack and data segments and then passes control here. Arguments:
BtRootDir - Address of root directory left in memory by boot sector BtBiosBlock - Address of bios parameter block. BtBootDrive - Drive that we booted from. Returns:
Does not return. Passes control to the OS loader --*/ {
ULONGLoaderEntryPoint; ULONGEisaNumPages; USHORTIsaNumPages;
MEMORY_LIST_ENTRY_far *CurrentEntry; PIMAGE_OPTIONAL_HEADEROptionalHeader; ULONGBlockEnd; ULONGImageSize; ULONGImageBase;
// 保存文件系统上下文信息
FsContext.BootDrive = (ULONG)BtBootDrive;
FsContext.PointerToBPB = MAKE_FLAT_ADDRESS(BtBiosBlock);
PatchDiskBaseTable();
// 基于总线类型设置机器类型. if (BtIsEisaSystem()) {
MachineType = MACHINE_TYPE_EISA; } else {
if (BtIsMcaSystem()) {
MachineType = MACHINE_TYPE_MCA; } else {
MachineType = MACHINE_TYPE_ISA; }
}
// 如果系统由软盘引导,那么关掉软盘驱动器 TurnMotorOff();
// 初始化视频子系统以使得错误和异常信息可以被显示 InitializeVideoSubSystem();
if (!ConstructMemoryDescriptors()) {
if (MachineType == MACHINE_TYPE_EISA) { IsaNumPages = IsaConstructMemoryDescriptors(); EisaNumPages = EisaConstructMemoryDescriptors(); if (EisaNumPages + 0x80 if (MachineType == MACHINE_TYPE_MCA) { McaConstructMemoryDescriptors(); } else { IsaConstructMemoryDescriptors(); } } } // 搜索内存描述符来表示低内存 CurrentEntry = MemoryDescriptorList; while ((CurrentEntry->BlockBase != 0) && (CurrentEntry->BlockSize != 0)) { CurrentEntry++; } if ((CurrentEntry->BlockBase == 0) && (CurrentEntry->BlockSize< (ULONG)512 * (ULONG)1024)) { BlPrint(SU_NO_LOW_MEMORY,CurrentEntry->BlockSize/1024); while (1) { } } // 确保osloader映像文件包含一个内存描述符 OptionalHeader = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)&edata + sizeof(IMAGE_FILE_HEADER)); ImageBase = OptionalHeader->ImageBase; ImageSize = OptionalHeader->SizeOfImage; OsLoaderBase = ImageBase; OsLoaderExports = ImageBase + OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; CurrentEntry = MemoryDescriptorList; while (ImageSize> 0) { while (CurrentEntry->BlockSize != 0) { BlockEnd = CurrentEntry->BlockBase + CurrentEntry->BlockSize; if ((CurrentEntry->BlockBase<= ImageBase) && (BlockEnd>ImageBase)) { // 该描述符至少得包含osloader的一部分代码 if (BlockEnd-ImageBase>ImageSize) { ImageSize = 0; } else { ImageSize -= (BlockEnd-ImageBase); ImageBase = BlockEnd; } // 寻找剩余一部分的代码 CurrentEntry = MemoryDescriptorList; break; } CurrentEntry++; } if (CurrentEntry->BlockSize == 0) { break; } } if (ImageSize> 0) { // 不能将osloader重定位到高内存位置,否则输出错误信息 BlPrint(SU_NO_EXTENDED_MEMORY); CurrentEntry = MemoryDescriptorList; while (CurrentEntry->BlockSize != 0) { BlPrint(\ %lx - %lx\\n\, CurrentEntry->BlockBase, CurrentEntry->BlockBase + CurrentEntry->BlockSize); CurrentEntry++; } while (1) { } } // 启用A20线 EnableA20(); // 重定位保护模式中使用的IDT和GDT结构 Relocatex86Structures(); // 首次开启保护模式和分页模式 EnableProtectPaging(ENABLING); // 重定位代码段并建立页面表项 LoaderEntryPoint = RelocateLoaderSections(&OsLoaderStart, &OsLoaderEnd); // 将控制权交给OS loader TransferToLoader(LoaderEntryPoint); } VOID NtProcessStartup( INPBOOT_CONTEXTBootContextRecord ) /*++ Routine Description: Main entry point for setup loader. Control is transferred here by the start-up (SU) module. Arguments: BootContextRecord - Supplies the boot context, particularly the ExternalServicesTable. Returns: Does not return. Control eventually passed to the kernel. --*/ { ARC_STATUSStatus; // 初始化引导加载器的显示功能 DoGlobalInitialization(BootContextRecord); BlFillInSystemParameters(BootContextRecord); if (BootContextRecord->FSContextPointer->BootDrive == 0) { // 从磁盘A:开始尝试引导 strcpy(BootPartitionName,\); GET_SECTOR(0,0,0,0,0,0,NULL); #ifdefined(ELTORITO) } elseif (BlIsElToritoCDBoot(BootContextRecord->FSContextPointer->BootDrive)) { // 从CD开始尝试引导 sprintf(BootPartitionName, \, BootContextRecord->FSContextPointer->BootDrive); ElToritoCDBoot = TRUE; #endif } else { //检查引导成功的分区是哪一个 BlGetActivePartition(BootPartitionName); } // 初始化内存描述符列表,OS loader的堆和参数块 Status = BlMemoryInitialize(); if (Status != ESUCCESS) { BlPrint(\); while (1) { } } // 初始化OS loader和I/O系统 Status = BlIoInitialize(); if (Status != ESUCCESS) { BlPrint(\); } BlStartup(BootPartitionName); // 永远不应该运行到这里! do { GET_KEY(); } while ( 1 ); } BOOLEAN BlDetectHardware( INULONGDriveId, INPCHARLoadOptions ) /*++ Routine Description: Loads and runs NTDETECT.COM to populate the ARC configuration tree. NTDETECT is assumed to reside in the root directory. Arguments: DriveId - Supplies drive id where NTDETECT is located. LoadOptions - Supplies Load Options string to ntdetect. Return Value: TRUE - NTDETECT successfully run. FALSE - Error --*/ { ARC_STATUSStatus; PCONFIGURATION_COMPONENT_DATATempFwTree; ULONGTempFwHeapUsed; externBOOLEANFwDescriptorsValid; ULONGFileSize; ULONGDetectFileId; FILE_INFORMATIONFileInformation; PUCHARDetectionBuffer; PUCHAROptions; UCHARBuffer[100]; LARGE_INTEGERSeekPosition; ULONGRead; // 检查在根目录下是否存在文件ntdetect.com,如果有的话就将其加载到预定义的位置并将控制权转交给他 #ifdefined(ELTORITO) if (ElToritoCDBoot) { // 假设ntdetect.com在i386目录下 Status = BlOpen( DriveId, \, ArcOpenReadOnly, &DetectFileId ); } else { #endif Status = BlOpen( DriveId, \, ArcOpenReadOnly, &DetectFileId ); #ifdefined(ELTORITO) } #endif DetectionBuffer = (PUCHAR)DETECTION_LOADED_ADDRESS; if (Status != ESUCCESS) { #ifDBG BlPrint(\, Status); BlPrint(\); while (!GET_KEY()) { } #endif return(FALSE); }