#001 /* Setup the Idle Thread */
#002 KeInitializeThread(InitProcess,
#003 InitThread,
#004 NULL,
#005 NULL,
#006 NULL,
#007 NULL,
#008 NULL,
#009 IdleStack);
......
#033
#034 /* Set up the thread-related fields inthe PRCB */
#035 Prcb->CurrentThread = InitThread;
#036 Prcb->NextThread = NULL;
#037 Prcb->IdleThread = InitThread;
#038
#039 /* Initialize the Kernel Executive */
#040 ExpInitializeExecutive(Number,LoaderBlock);
上面这句就是调用函数ExpInitializeExecutive来初始化内核执行体的功能,它是内核所有功能管理初始化,比如内核对象管理器,内核内存管理,还有硬件抽象层HAL的初始化。具体的部分代码如下:
#001 VOID
#002 NTAPI
#003 ExpInitializeExecutive(IN ULONG Cpu,
#004 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
#005 {
#006 PNLS_DATA_BLOCK NlsData;
#007 CHAR Buffer[256];
#008 ANSI_STRING AnsiPath;
#009 NTSTATUS Status;
#010 PCHAR CommandLine, PerfMem;
#011 ULONG PerfMemUsed;
#012 PLDR_DATA_TABLE_ENTRY NtosEntry;
#013 PRTL_MESSAGE_RESOURCE_ENTRY MsgEntry;
#014 ANSI_STRING CsdString;
#015 ULONG Remaining = 0;
#016 PCHAR RcEnd = NULL;
#017 CHAR VersionBuffer [65];
#018
#019 /* Validate Loader */
#020 if (!ExpIsLoaderValid(LoaderBlock))
#021 {
#022 /* Invalid loader version */
#023 KeBugCheckEx(MISMATCHED_HAL,
#024 3,
#025 LoaderBlock->Extension->Size,
#026 LoaderBlock->Extension->MajorVersion,
#027 LoaderBlock->Extension->MinorVersion);
#028 }
上面主要检查引导参数是否正确,如果不正确就进入处理出错,直接停在出错位置上,把出错码输出。
#029
#030 /* Initialize PRCB pool lookasidepointers */
#031 ExInitPoolLookasidePointers();
上面是初始化PRCB里的后备列表缓冲区指针,那么什么是后备列表呢?堆管理器管理着系统和用户的堆内存,它把堆空间分为相同尺寸的块(block)。堆管理器会根据堆分配请求,去选择一个合适尺寸的未使用的块。显然,这个过程需要点时间。如果你需要固定尺寸的内存块,但是你事先并不知道它的大小和使用频率,这样的话为了性能的原因,你还是使用后备列表(Lookaside Lists)的,后备列表是只有内核模式才有的。
后备列表和系统内存池的主要的区别是什么呢?后备列表只可以分配固定大小的事先定义尺寸的内存块。后备列表会快很多,因为它不需要去搜索可用的未分配的内存。
当你刚接触后备列表,你需要解决的问题不是怎么创建后备列表,而是管理你要分配的内存块。
后备列表(lookaside list)是一组事先分配的相同尺寸的内存块。这些块有些在使用,有些没被使用。当有内存分配请求的时候,系统会遍历这个列表寻找最近的未分配的块。如果未分配的块找到了,分配请求就很快被满足了。否则系统必须从分页或不分页内存池去分配。根据列表中分配行为发生的频率,系统会自动调整未分配块的数量来满足分配请求,分配的频率越高,会有越多的块被存储在后备列表中。后备列表如果总是不被使用,也会自动减少空间大小。
其实后备列表就是保存一些最近使用的空闲内存的内存块。