nt4源码剖析之Ntoskrnl篇.docx_第1页
nt4源码剖析之Ntoskrnl篇.docx_第2页
nt4源码剖析之Ntoskrnl篇.docx_第3页
nt4源码剖析之Ntoskrnl篇.docx_第4页
nt4源码剖析之Ntoskrnl篇.docx_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第一章 ntoskrnl2一 系统启动3二 Idle进程6三 初始化内核71 内核初始化综述72初始化内核结构103初始化进程对象114初始化线程对象125初始化执行体156初始化硬件体系层187初始化执行体组件21第一章 ntoskrnlNtoskrnl程序位于privatentosinit目录下,其入口有2个:ntkrnlmp.c、ntoskrnl.c,但ntkrnlmp.c只有一句代码:#include ntoskrnl.c,2个其实是1个。ntoskrnl的主函数里仅仅调用了KiSystemStartup函数,ntoskrnl的入口函数还是要看KiSystemStartup函数了。一 系统启动KiSystemStartup函数_KiSystemStartup函数的实现代码位于privatentoskei386newsysbg.asm文件中。这个模块是台湾的宗世麟(Shie-Lin Tzong (shielint)在1990年编写的,国立台湾大学82届资讯系毕业,他编写了nt4内核的X86汇编代码。(遐想:Windows内核代码居然有台湾人参与,但中国大陆却无人参与,可叹!难道中国只能开发应用软件,无人能做系统软件的开发吗?别跟我提那些只会做皮不会写瓤的中国Linux厂商。)启用每个CPU时都会调用此函数,分2种情况:启动CPU、其他CPU,执行操作有细微不同。CPU的数量保存在几个变量中(_KeNumberProcessors、KissPbNumber)。CPU0使用的线程对象、堆栈空间是静态内存,线程对象(ETHREAD)是P0BootThread,堆栈空间是P0BootStack,大小03000H(12K)。CPU0设置FS=KGDT_R0_PCR(030H)。所有的CPU都调用KiInitializeMachineType函数获取机器类型,函数位于privatentoskei386i386init.c文件中。机器类型保存在加载参数块中(计算方法:KeLoaderBlock-u.I386.MachineType & 0x000ff),各个字节的含义如下:字节含义Byte 0Machine Type, ISA, EISA or MCAByte 1CPU type, i386 or i486Byte 2Cpu Step, A or B . etcHighest bitindicates if NPX is present调用GetMachineBootPointers函数获取相关的gdt、pcr、tss、idt地址,调用sgdt指令加载gdt获取地址,通过FS保存的PCR选择子获取PCR地址,通过str指令加载TSS选择子获取TSS地址,通过sigt指令加载idt获取地址。GDT中的TSS(28h) 描述符是16位的,需要修改为32位,初始化TSS,加载此TSS选择子到TR寄存器。286CPU使用16位TSS格式。TSS描述符的第5个字节设置为89h(dpl=0, present, TSS32, not busy),则设置成了32位TSS。初始化TSS分2种情况,1种是初始化静态不变的TSS成员(KiInitializeTSS),1种是初始化仅需要设置1次的成员(KiInitializeTSS2函数)。KiInitializeTSS函数设置TSS静态成员。IoMapBase 设置为IO_ACCESS_MAP_NONE的IOPM偏移地址,在V86模式时IO进入硬件。flag(T)为0,任务切换时不引起调试异常。LDT 为0,即不使用LDT。Ss0为KGDT_R0_DATA(010H)。KiInitializeTSS2函数设置仅需要设置1次的成员。Limit设置为(sizeof(KTSS) - 1)。TSS有2张MAP,Tss-IoMaps中的IoMap设置为-1。Tss-IoMaps中的DirectionMap(软中断重定向)设置为0。Tss-IntDirectionMap(IO_ACCESS_MAP_NONE)设置为0,设置双重错误(double fault)、NMI中断的任务门。需要设置IDT、GDT、TSS。双重错误任务门是8号中断,位于IDT中的40h,设置任务门的05h字节为85h(dpl=0, present, taskgate),任务门的02h字节(TSS Segment Selector)为KGDT_DF_TSS。双重错误任务门的门描述符位于GTD+KGDT_DF_TSS,05字段设置为089h,基地值BASE设置为_KiDoubleFaultTSS,LIMIT设置为MINIMUM_TSS_SIZE(068H)。调用_KiInitializeTSS函数初始化TSS段_KiDoubleFaultTSS,CR3设置为当前CPU的CR3,EIP=_KiTrap08,eflags=0,CS= KGDT_R0_CODE, FS= KGDT_R0_PCR,ss=当前CPU的SS,Es=Ds=KGDT_R3_DATA OR RPL_MASK。TSS的堆栈ESP=ESP0,在DBG模式时,设置为_KiDoubleFaultStack;构建时,把内核镜像的ZW thunks部分作为堆栈,即(FLAT:_ZwUnmapViewOfSection8 - 4)&(3),此时先检验ZW thunks区域大小是否小于0a00h,ZW thunks区域大小计算方式:(FLAT:_ZwUnmapViewOfSection8 - 4)&(3)-FLAT:_ZwAcceptConnectPort24),如果大于,则显示错误信息DF Stack internal error。NMI中断任务门是2号中断,位于IDT中的10h,设置任务门的05h字节为85h(dpl=0, present, taskgate),任务门的02h字节(TSS Segment Selector)为KGDT_NMI_TSS。NMI中断任务门的门描述符位于GTD+KGDT_NMI_TSS,05字段设置为089h,基地值BASE设置为_KiNMITSS,LIMIT设置为MINIMUM_TSS_SIZE(068H)。调用_KiInitializeTSS函数初始化TSS段_KiNMITSS,CR3设置为当前CPU的CR3,堆栈ESP=ESP0= DoubleFault的TSS堆栈,EIP= _KiTrap02,eflags=0,CS= KGDT_R0_CODE, FS= KGDT_R0_PCR,ss=当前CPU的SS,Es=Ds=KGDT_R3_DATA OR RPL_MASK。_KiInitializePcr函数初始化处理器的PCR,每个处理器含有自己的GDT、IDT、TSS。把当前线程对象中的进程地址设置为_KiIdleProcess地址。KissIdleThread+ThApcState+AsProcess = offset FLAT:_KiIdleProcess。设置PCR-Teb = 0,设置KernelDr7和KernelDr6为 0。_KiSwapIDT函数交换IDT描述符的(Segment Selector)和(Offset 31.16)数据,因为IDT表是按照IDTEntry宏定义设置的,这2个数据的位置是错位的,交换即可。设置DS=ES= KGDT_R3_DATA OR RPL_MASK。复制陷阱句柄替换内核调试句柄,但保留double fault和nmi fault。先把double fault和nmi fault的描述符push到堆栈,再复制_IDT的数据到kissIDT,最后从堆栈中pop出double fault和nmi fault的描述符。如果是新处理器,则先获取freezelock,再更新CPU广播位,调用_HalInitializeProcessor初始化CPU,调用_KiInitializeAbios初始化ABIOS数据,增加处理器计数,最后释放freezelock。_HalInitializeProcessor函数初始化CPU的PCR,PcIDR=0fffffffbh,启用次IRQ;PcStallScaleFactor=INITIAL_STALL_COUNT(064H)。_KiInitializeAbios函数初始化GDT空闲列表,且设置KiI386AbiosCall选择子。从KeLoaderBlock中获取CommonDataArea,检验CommonDataArea是否为空,处理器是否是0,初始化KiAbiosGdtLock、KiAbiosLidTableLock,调用KiAbiosGetGdt函数获取GDT(即fs:PcGdt),调用KiInitializeAbiosGdtEntry函数初始化16位堆栈段、数据段、代码段,如果是P0,调用Ki386InitializeGdtFreeList函数初始化GDT空闲列表。GDT保留了3个选择子给16位的堆栈段、代码段、数据段,以便在i386模式下调用BIOS中断。16位段描述符大小类型堆栈段KGDT_STACK16(0xf8)00xFFFFTYPE_DATA(0x12)数据段KGDT_CDA16(0xe8)Common Data Area0xFFFFTYPE_DATA(0x12)代码段KGDT_CODE16(0xf0)KiI386AbiosCall函数TYPE_CODE(0x18)Ki386InitializeGdtFreeList函数初始化GDT空闲列表,GDT开始处的28个项为保留的,从GDT末尾开始,如果GDT项的Present为0,则链接GDT列表的Flink,最后一项的Flink为0。检验处理器号,如果是0,则先调用_KdInitSystem初始化系统,再调用POLL_DEBUGGER给调试器一个机会获取控制权。POLL_DEBUGGER宏调用_KdPollBreakIn函数检验是否进入调试模式,如果是,则调用_DbgBreakPointWithStatus函数进入调试模式,且状态值是DBG_STATUS_CONTROL_C(01H)。_DbgBreakPointWithStatus函数把参数(状态值)放在EAX,调用int 3进入调试模式。调用KfRaiseIrql函数提升IRQL到HIGH_LEVEL。检验P0处理器是否支持cmpxchg8b指令,如果不支持,则修改使用此指令的函数,使其跳转到使用SpinLock的相应函数。先通过检验EFLAGS寄存器的bit21位是否设置、清除来查看是否支持cpuid指令,如果不能,则修改函数。如果能,则eax赋值1,执行cpuid指令,查看edx寄存器的bit8位,如果是0,则修改函数,如果是1,则支持cmpxchg8b指令,设置变量_KiBootFeatureBits的bit7位为1(KF_CMPXCHG8B=0x00000080)。修改4个函数:原函数目标函数ExInterlockedCompareExchange64ExpInterlockedCompareExchange64ExInterlockedPopEntrySListExfInterlockedPopEntrySListExInterlockedPushEntrySListExfInterlockedPushEntrySList_ExInterlockedExchangeAddLargeInteger_ExInterlockedAddLargeInteger修改方法,把原函数的入口处的代码修改为jmp指令,跳转到目标函数。先获取原函数、目标函数的地址,原函数的首字节为0e9h(Jump near),计算目标函数和jmp语句的偏移,赋值给原函数的第25字节。初始化寄存器,调用_KiInitializeKernel函数初始化系统数据结构、硬件。设置当前线程的属性为实时优先线程。fs:PcPrcbData+PbCurrentThread+ThPriority = LOW_REALTIME_PRIORITY空闲线程在IRQL为HIGH_LEVEL时返回控制权,则开中断,调用KfLowerIrql函数降低IRQL到DISPATCH_LEVEL,设置空闲线程的ThWaitIrql为DISPATCH_LEVEL。在多处理器中,P0直接计进入idle循环,其他处理去,则需要等待_KiBarrierWait障碍,当_KiBarrierWait为0时,才能进入idle循环。最后进入Idle进程。二 Idle进程这个进程执行空循环且永不返回。并且根据当前CPU号决定是否进入调试系统、执行DPC、切换线程等功能。(见KiIdleLoop函数)空循环就2条指令:sti、hlt,开中断,停止当前CPU指令的执行,执行电源管理。如果当前CPU号是最低的,且breakin轮询值为0,则进入调试系统。轮询值从20000开始,逐次递减。从当前CPU的PCR中获取DPC列表,如果不为空,则设置中断级别为DISPATCH_LEVEL,清理软件中断,开始处理PDC列表。完毕以后,breakin轮询值清零。如果当前CPU的DPC列表为空,则检查下一个要执行的线程,如果没有,则进入空循环;如果有,则切换线程,执行下一个线程的DPC。切换线程时,先获取_KiDispatcherLock锁,提升IRQL为SYNCH_LEVEL,开中断,获取下一个线程的地址,禁用APC中断,切换线程上下文,把IRQL降低到DISPATCH_LEVEL。处理PDC列表时,设置DPC程序激活值,占用DPC锁,从DPC列表中获取当前DPC项,移除此项,保存当前中断事件、数量等,获取DPC对象的参数,清理DPC插入标记,减少DPC深度,释放DPC锁,开中断,调用DPC延迟函数。(见KiRetireDpcList函数)调用完成后,要检查当前IRQL、堆栈、运行时间。如果当前IRQL不等于DISPATCH_LEVEL,则报IRQL_NOT_GREATER_OR_EQUAL蓝屏;如果执行前后堆栈不相等,则打印DPC破坏ESP的信息,清堆栈,进入调试器,处理下一个DPC函数;如果运行时间超时,则打印DPC超时的信息,再检查是否启动调试模式,如果有,则进入调试系统,如果没有,则处理下一个DPC函数。如果都正常,则清堆栈,执行下一个DPC函数。DPC列表执行完毕后,清理DPC程序激活值,清DPC中断请求值,返回。三 初始化内核1 内核初始化综述KiInitializeKernel函数此函数位于privatentoskei386kernlini.c文件中。功能是初始化内核数据结构、idle线程进程对象、PCB,调用执行体初始化函数,返回到系统启动程序,当新的处理器上线时也会调用这个函数初始化处理器指定的结构。调用KiSetProcessorType函数设置CPU类型、步进,保存到CPU的PRCB中。先尝试更改EFLAGS寄存器的ID位(bit 21),检验是否支持CPUID指令,如果能更改,则支持,调用CPUID获取CPU类型;如果不能更改,则不支持CPUID指令,尝试更改EFLAGS寄存器的AC位(bit 18),如果能更改,则是386,再调用Get386Stepping函数获取步进;如果不能更改,则是486,再调用Get486Stepping函数获取步进。调用CPUID指令之前,先把Trap6改为临时处理无效指令的异常处理代码,当调用CPUID时,发生此异常,则先恢复Trap6的原始异常处理代码,再进行处理器判断(386或486)。先设置CPUID参数(EAX)为0,调用CPUID指令,如果EAX值大于3,则是586;如果小于1,则进行(386或486)处理器判断;如果是其他值,则再设置CPUID参数(EAX)为1,调用CPUID指令,EAX的bit13、bit14位则是处理器类型。调用Get386Stepping函数获取386步进。先调用386的32bit乘法指令mul,如果失败,则步进为0;如果成功,则调用xbts指令,如果失败,则步进为B0(100h);如果成功,则更改调试异常(Trap1)为临时Trap1处理代码,设置EFLAGS寄存器的TF位(bit 8),调用popfd指令,如果产生调试异常,则步进为D1(301h);如果没有,则步进为B1(101h)。调用Get486Stepping函数获取486步进。如果CRO的ET位 (bit 4)为1,且不能被清除,则步进为A(0);如果能被清除,则执行mov eax, DR4指令,如果产生Trap06异常,则步进为B(100h);否则,则调用_KiIsNpxPresent函数检验Npx是否存在,如果不存在,则步进为C(200h);如果存在,则调用FPU相关指令,如果执行失败,则步进为C(200h);如果成功,则步进为D(300h)。调用_KiSetCR0Bits函数设置CRO位,如果CPU类型高于386,则设置CR0的WP位(bit16)。调用KiIsNpxPresent函数检验数字附处理器是否存在,且根据NPX是否存在、CPU类型设置CRO寄存器值。先调用fninit指定初始化NPX,再调用fnstsw指令获取状态,如果状态是0,则NPX存在,否则不存在。先清理CRO的ET、MP、TS、EM位,如果不存在NPX,则只EM、TS置位,如果存在NPX,则ET也置位,如果CPU类型高于386,则NE也置位。调用KeGetPcr函数获取PCR地址,即PCR的PcSelfPcr(01CH)值。当定义NT_UP时,PCR等于0FFDFF000H,否则PCR等于FS寄存器的值。NT_UP是当在单处理器上创建OS时才定义的,打开各种各样的在单CPU时使用的已知的short-cuts。(NT_UP is defined when the uniprocessor build of the o/s is created, and turns on various short-cuts that can be used when it is known that only a single CPU is present.)初始化PRCB的DPC列表、DPC锁、其他成员。检验PRCB的CPU类型,仅仅支持NONE、INTEL、AMD三种类型,如果是CYRIX处理器,则报(UNSUPPORTED_PROCESSOR,0x386,0,0,0)蓝屏。如果是P0处理器,初始化设置CPU类型、步进、型号、级别、版本等。调用KiGetFeatureBits函数获取CPU特征。如果BOOT时支持cmpxchg8b指令,检验获取到的CPU特征是否支持cmpxchg8b指令,如果不支持,则报(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_CMPXCHG8B, 0, 0, 0)蓝屏。降低IRQL到APC_LEVEL级别。初始化内核内部锁KiContextSwapLock、KiDispatcherLock、KiFreezeExecutionLock。调用KiInitSystem函数初始化CPU独有的结构。调用KeInitializeProcess函数初始化idle线程进程对象,基本优先级(BasePriority)为0,亲和性(Affinity)为0xffffffff,页目录表(DirectoryTableBase)为0,是否自动对齐(AutoAlignment)为FALSE,线程时限(ThreadQuantum)为MAXCHAR(0x7f)。如果是其他处理器,调用KiGetFeatureBits函数获取CPU特征。系统中的所有CPU对NPX的有效性必须一致,要么全支持,要么全不支持,如果不一致,则报(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, 0x387, 0, 0, 0)蓝屏。检验CPU类型、步进,获取所有CPU的最低类型、步进。检验所有CPU对KF_CMPXCHG8B指令的有效性是否一致,如果不一致,则报(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_CMPXCHG8B, 0, 0, 0)蓝屏。检验所有CPU对KF_GLOBAL_PAGE的有效性是否一致,如果不一致,则报(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED, KF_GLOBAL_PAGE, 0, 0, 0)蓝屏。获取所有CPU的最小的步进。获取所有的CPU特征位的交集。降低IRQL到DISPATCH_LEVEL。系统分配了64K的共享数据区,内核、用户共享,地址范围是0xffdf00000xffdfffff。在osloader中(BlSetupForNt函数)已经设置好相关的页目录表、页表等。共享数据区是KUSER_SHARED_DATA结构。这里仅仅更新此结构的ProcessorFeatures(处理器特征位),ProcessorFeatures是大小为64的BOOLEAN类型数组,每个数组成员表示处理器的某个特征,目前定义了4个特征,分别是:这里根据变量KeFeatureBits设置此数组。KeFeatureBits的bit8位是MMX指令有效位,如果是1,则PF_MMX_INSTRUCTIONS_AVAILABLE为TRUE,否则,为FALSE; KeFeatureBits的bit7位是CMPXCHG8B指令有效位,如果是1,则PF_COMPARE_EXCHANGE_DOUBLE为TRUE,否则,为FALSE。调用KeInitializeThread函数初始化idle线程对象,设置线程对象的初始化内核堆栈(InitialStack)、堆栈基地址(StackBase)为((ULONG)IdleStack) &0xfffffff0),堆栈最低地址(StackLimit)为(ULONG)Thread-InitialStack - KERNEL_STACK_SIZE),KERNEL_STACK_SIZE在AMD上为24K(0x6000),在i386上为12K(12288)。下一个处理器号(NextProcessor)为参数中的Number。优先级(Priority)为HIGH_PRIORITY。状态(State)为Running。亲和性(Affinity)为(KAFFINITY)(1Number)。等待IRQL(WaitIrql)为DISPATCH_LEVEL。设置进程的激活处理器号(ActiveProcessors)为(ActiveProcessors | (1 Header.WaitListHead)。初始化线程的APC队列锁(ApcQueueLock),用于保护线程的APC队列。设置线程的线程环境块(Teb)为参数中的Teb。设置线程的初始化堆栈(InitialStack)、堆栈基地址(StackBase)为参数中的KernelStack,设置堆栈限制(StackLimit)为((PVOID)(ULONG)KernelStack - KERNEL_STACK_SIZE)),这几个成员都与堆栈相关,InitialStack为堆栈的原始位置,StackBase为当前栈的基地址,StackLimit为栈的低地址。调用KiInitializeContextThread函数初始化线程上下文,线程上下文主要用于线程切换。设置线程的基本优先级(BasePriority)、优先级(Priority)、亲和性(Affinity)、用户亲和性(UserAffinity)、Quantu、DisableBoost为进程的相应值。设置是否激活系统亲和性(SystemAffinityActive)为FALSE。设置状态(State)为Initialized。Priority是可调整的优先级。BasePriority为初始的优先级。设置线程Iopl为进程的Iopl。调用InsertTailList函数把线程插入到进程的线程列表(ThreadListHead)尾部,递增进程的内核堆栈数量(StackCount),如果StackCount为MAXSHORT,表明此进程尚未创建线程,则设置StackCount为1;否则加1。递增进程的ThreadSeed。设置线程的理想处理器(IdealProcessor)为((UCHAR)(Process-ThreadSeed % KeNumberProcessors))。在此过程中,必须锁分发器数据库,调用KiLockDispatcherDatabase函数锁分发器数据库,调用KiUnlockDispatcherDatabase函数解锁分发器数据库。KiInitializeContextThread函数初始化线程上下文。线程分用户线程和内核线程,堆栈结构不同,用户线程比内核线程多陷阱框架(KTRAP_FRAME)。堆栈结构高地址| |低地址用户线程内核线程FLOATING_SAVE_AREAFLOATING_SAVE_AREAKTRAP_FRAMEUserContextFlagUserContextFlagStartContextStartContextStartRoutineStartRoutineSystemRoutineSystemRoutineKSWITCHFRAMEKSWITCHFRAME如果参数中的上下文框架(ContextFrame)存在,则是用户线程,否则,是内核线程。如果是用户线程,从线程的初始堆栈中分配FLOATING_SAVE_AREA区域,再分配陷阱框架(KTRAP_FRAME)区域,再分配用户上下文标记(UserContextFlag)、开始上下文(StartContext)、开始函数(StartRoutine)、系统函数(SystemRoutine)区域,最后分配KSWITCHFRAME区域。新建一个上下文框架,复制参数中的上下文框架,初始化FloatSave,根据NPX是否存在(KeI386NpxPresent),设置化上下文框架的NPX状态,强制关闭上下文框架的调试寄存器,设置上下文标记(ContextFlags)为不带CONTEXT_DEBUG_REGISTERS位(0x00010000 | 0x00000010L)。调用KeContextToKframes函数把新建的上下文框架(ContextFrame)信息复制到陷阱框架(KTRAP_FRAME),设置KTRAP_FRAME的HardwareSegSs、SegDs、SegEs的请求特权级(RPL)为RPL_MASK(3)。设置用户上下文标记(UserContextFlag)为1,标志用户上下文存在。设置陷阱框架的异常列表(ExceptionList)为EXCEPTION_CHAIN_END(struct _EXCEPTION_REGISTRATION_RECORD *)-1),上上次模式(PreviousPreviousMode)为用户模式(UserMode)。设置线程的上一次模式(PreviousMode)为用户模式(UserMode)。如果是内核线程,从线程的初始堆栈中分配FLOATING_SAVE_AREA区域,再分配用户上下文标记(UserContextFlag)、开始上下文(StartContext)、开始函数(StartRoutine)、系统函数(SystemRoutine)区域,最后分配KSWITCHFRAME区域。初始化FLOATING_SAVE_AREA区域,Cr0NpxState为0。设置线程的NPX状态(NpxState)为 NPX_STATE_NOT_LOADED。设置用户上下文标记(UserContextFlag)为0,标志不存在用户上下文。设置线程的上一次模式(PreviousMode)为内核模式(KernelMode)。至此,用户线程、内核线程的独立部分设置完成,后面的设置不分用户、内核线程。设置线程的开始参数,开始上下文(StartContext)、开始函数(StartRoutine)、系统函数(SystemRoutine)为参数中的相应值。设置KSWITCHFRAME的返回地址(RetAddr)为KiThreadStartup函数地址,设置标记(Eflags)为EFLAGS_INTERRUPT_MASK(0x00000200L),设置异常列表(ExceptionList)为EXCEPTION_CHAIN_END。设置线程的内核堆栈地址(KernelStack)为KSWITCHFRAME的地址。KeContextToKframes函数根据上下文的标记(ContextFlags)把上下文框架(ContextFrame)的内容移动到陷阱框架(TrapFrame)中。陷阱框架(TrapFrame)的内容包含调试系统用到的值、框架被编辑时的临时值、调试寄存器、段寄存器、通用寄存器、状态、非通用寄存器、控制寄存器,#define CONTEXT_i386 0x00010000如果ContextFlags含有CONTEXT_CONTROL值(CONTEXT_i386 | 0x00000001L),则设置TrapFrame的控制寄存器。如果ContextFlags含有CONTEXT_SEGMENTS值(CONTEXT_i386 | 0x00000004L),则设置TrapFrame的段寄存器、V86段寄存器。如果ContextFlags含有CONTEXT_INTEGER值(CONTEXT_i386 | 0x00000002L),则设置TrapFrame的通用寄存器、非通用寄存器。如果ContextFlags含有CONTEXT_FLOATING_POINT值(CONTEXT_i386 | 0x00000008L),则设置TrapFrame的浮点寄存器。如果ContextFlags含有CONTEXT_DEBUG_REGISTERS值(CONTEXT_i386 | 0x00000010L),则设置TrapFrame的调试寄存器。如果线程含有IOPL,则设置EFlags含有EFLAGS_IOPL_MASK值(0x00003000L)。5初始化执行体ExpInitializeExecutive函数初始化执行体、子组件。如果是P0处理器,则初始化很多东西。根据LoaderBlock-SetupLoaderBlock值,设置ExpInTextModeSetup值,如果SetupLoaderBlock为TRUE ,则ExpInTextModeSetup为TRUE,否则为 FALSE。设置InitializationPhase为0。统计物理内存块,调用MmInitializeMemoryLimits函数,遍历参数LoaderBlock的内存描述符列表(MemoryDescriptorListHead)统计,但不统计内存类型是LoaderBad、LoaderFirmwarePermanent、LoaderSpecialMemory的内存块,保存到PHYSICAL_MEMORY_DESCRIPTOR类型的内存中。初始化交换表,先根据LoaderBlock的NlsData,获取NlsTableBase的值,获取AnsiCodePage、OemCodePage、UnicodeCaseTable的偏移地址,再调用RtlInitNlsTables函数初始化Nls表,再调用RtlResetRtlTranslations函数重置Nls表(InitTableInfo)。调用HalInitSystem函数初始化硬件体系层(HAL),如果初始化失败,则报HAL_INITIALIZATION_FAILED蓝屏。调用KiRestoreInterrupts函数启用中断。设置Sh

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论