大概看了些内存管理的东西,整理一下笔记,陆续贴上来。
参考《Windows Internals》、《Windows内核原理与实现》、WRK。调试环境WRK x86,非PAE。
开始时比较乱,因为还没想好要如何排版 ,不过反正开头都是些基础东西,匆匆带过好了
一、概述,内存管理一些基础
主要要实现的功能:
1. 进程间内存实现隔离
2.内存的申请和释放
3. 主存和辅存页面的换入和换出(包括页面映射文件)
大致分为用户模式空间管理,系统空间管理,还有物理内存的管理
页式内存管理基础(实现功能1):
虚拟地址对物理地址的转换,实现进程间内存的隔离。
还有页目录,系统映像大小等等一系列全局变量。整体划分情况
3 建立页目录 页表 初始化非换页内存池 等实质性的工作MiInitMachineDependent 真正实现虚拟内存的机制
4. MmInitializeMemoryLimits 获取物理内存信息,并且申请一个位图来记录物理页面是否有效
5. MiReloadBootLoadedDrivers (LoaderBlock); ntldr把启动驱动放在了80000000处,现在可以开始重定位到系统pte处了
6.确定系统内存规模,建立系统缓存和系统缓存工作集
7 MiBuildPagedPool ();建立换页池
至此系统空间的定义和初始化都已经完成了,初始化了一下PsLoadedModuleList,由MiInitializeLoadedModuleList实现
1阶段:
主要工作:创建\\Device\\PhsicalMemory的内存区对象,设置MmSharedUserDataPte 使得0xffdf0000和0x7ffe0000共享内存
初始化会话空间
开启修改页面写出器
初始化内存事件
开启平衡及管理器KeBalanceSetManager KeSwapProcessOrStack两个线程
开启零化内存线程
对加载模块设置保护属性
2阶段:
设置加载模块PAGE段为可换页的
参考《Windows Internals》、《Windows内核原理与实现》、WRK。调试环境WRK x86,非PAE。
开始时比较乱,因为还没想好要如何排版 ,不过反正开头都是些基础东西,匆匆带过好了
一、概述,内存管理一些基础
主要要实现的功能:
1. 进程间内存实现隔离
2.内存的申请和释放
3. 主存和辅存页面的换入和换出(包括页面映射文件)
大致分为用户模式空间管理,系统空间管理,还有物理内存的管理
页式内存管理基础(实现功能1):
虚拟地址对物理地址的转换,实现进程间内存的隔离。
虚拟地址的意义:
查询物理页面的过程
多层查表效率受到影响,CPU有自己的缓存:TLB
PDE&PTE 的意义
工作集:
进程当前正在使用的物理页面的集合。如果页面未被访问,却在工作集中,不会被换出
WIN内存管理概述:
★ 段式管理被屏蔽,CS SS DS ES 在GDT中所对应的段基地址都是0,段最大偏移是0xffff000
★ 进程的虚拟地址分配情况 用VAD描述
★ 物理内存页面状态 PFN库来描述
★ 相同类型的页面用链表连接
★ 使用异常来处理换页
★ 工作及管理器 对进程的工作集加以修剪
主要组件:
执行体层面 提供内存管理的服务(也包括底层的支持)
异常处理 换页
系统线程 平衡集管理器 1s一次 全局管理
进程栈交换器 线程切换时,如果一个进程无active thread时,进程的内存页可被换出(换出的是进程的4个最基本页面…)
0页面线程 负责内存0化
修改页面写出器
===============================================================
二、系统对内存空间的初始化(出现大量名词...但只是简要流程,细节要看过管理算法再讨论~):
BOOLEAN
MmInitSystem (
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This function is called during Phase 0, phase 1 and at the end
of phase 1 ("phase 2") initialization.
Phase 0 initializes the memory management paging functions, 初始化内存管理换页函数,内存池,PFN数据库
nonpaged and paged pool, the PFN database, etc.
Phase 1 initializes the section objects, the physical memory 初始化section对象 物理内存对象 开启内存管理的系统线程
object, and starts the memory management system threads.
Phase 2 frees memory used by the OsLoader. 释放内存
MmInitSystem在执行体初始化函数ExpInitializeExecutive 中调用,
0阶段:
1 初始化了临时事件
KeInitializeEvent (&MiTempEvent, NotificationEvent, FALSE);
MiLowMemoryEvent = &MiTempEvent;
MiHighMemoryEvent = &MiTempEvent;
MiLowPagedPoolEvent = &MiTempEvent;
MiHighPagedPoolEvent = &MiTempEvent;
MiLowNonPagedPoolEvent = &MiTempEvent;
MiHighNonPagedPoolEvent = &MiTempEvent;
2 0阶段中划分了系统内存空间,一些全局变量被设置,比如
MmHighestUserAddress = (PVOID)(KSEG0_BASE - 0x10000 - 1);
MmUserProbeAddress = KSEG0_BASE - 0x10000;
MmSystemRangeStart = (PVOID)KSEG0_BASE;
还有页目录,系统映像大小等等一系列全局变量。整体划分情况
其中Session space又按照 会话内存池(16M,属于会话空间的换页内存池) 会话视图(20M) SESSION WS 会话映像文件(win32k 视频驱动 打印驱动的映像文件) 的顺序排列
MiInitMachineDependent (LoaderBlock);
MmPhysicalMemoryBlock = MmInitializeMemoryLimits (LoaderBlock,
IncludeType,
NULL);
3 建立页目录 页表 初始化非换页内存池 等实质性的工作MiInitMachineDependent 真正实现虚拟内存的机制
MiInitMachineDependent:
设置当前进程的页目录
PointerPte = MiGetPdeAddress (PDE_BASE);
PdePageNumber = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
CurrentProcess = PsGetCurrentProcess ();
DirBase = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) << PAGE_SHIFT;
CurrentProcess->Pcb.DirectoryTableBase[0] = DirBase;
//
// Unmap the low 2Gb of memory.
//
PointerPde = MiGetPdeAddress (0);
LastPte = MiGetPdeAddress (KSEG0_BASE);
MiZeroMemoryPte (PointerPde, LastPte - PointerPde); 清空了0~2GB的目录 这是空闲进程,没有用户空间
接下来的大段代码就是计算Pfn数据库和非换页内存池得大小,然后开始分配系统PTE和扩展的非换页内存池的页表
StartPde = MiGetPdeAddress (MmNonPagedSystemStart); 获得开始和结束的目录项
EndPde = MiGetPdeAddress ((PVOID)((PCHAR)MmNonPagedPoolEnd - 1));
while (StartPde <= EndPde) {
ASSERT (StartPde->u.Hard.Valid == 0);
//
// Map in a page table page, using the
// slush descriptor if one exists.
//
TempPde.u.Hard.PageFrameNumber = MxGetNextPage (1, TRUE);
*StartPde = TempPde; 赋值一个分配好的目录项,申请了物理内存,需要对其进行清零,但现在没有建立起页表的映射,如何反查页目录的虚拟内存地址?
PointerPte = MiGetVirtualAddressMappedByPte (StartPde);
左移10位,这个操作基于页目录的自映射方案,在页目录访问自己时,0xc0000000的虚拟地址对应查表PDE_BASE+0xc00,也就是0xc00指向的是0xc0000000的地址 这下0xc0000000便作为PTE 二次查表 关于自映射方案 可以阅读
http://hi.baidu.com/wzt85/blog/item/a28aec0f01c7dc276159f377.html 作者 wzt85
RtlZeroMemory (PointerPte, PAGE_SIZE);
StartPde += 1;
接下来分配PFN数据库和非换页内存池了
MmPfnDatabase 是MMPFN的数组,记录了物理页面的状态
MmFreePagesByColor 初始化
MmFreePagesByColor[1] = &MmFreePagesByColor[0][MmSecondaryColors];
for (i = 0; i < MmSecondaryColors; i += 1) {
MmFreePagesByColor[ZeroedPageList][i].Flink = MM_EMPTY_LIST;
MmFreePagesByColor[ZeroedPageList][i].Blink = (PVOID) MM_EMPTY_LIST;
MmFreePagesByColor[ZeroedPageList][i].Count = 0;
MmFreePagesByColor[FreePageList][i].Flink = MM_EMPTY_LIST;
MmFreePagesByColor[FreePageList][i].Blink = (PVOID) MM_EMPTY_LIST;
MmFreePagesByColor[FreePageList][i].Count = 0;
}
PFN数据库与物理页面实际状态同步
初始化非换页内存池,系统PTE池
最后针对本进程建立起一些列相关的内容,以及工作及链表,建立PDE映射超空间,进程的VAD等等内容,等到后面再细看了
4. MmInitializeMemoryLimits 获取物理内存信息,并且申请一个位图来记录物理页面是否有效
Bitmap = ExAllocatePoolWithTag (
NonPagedPool,
(((MmHighestPossiblePhysicalPage + 1) + 31) / 32) * 4,
' mM');
if (Bitmap == NULL) {
KeBugCheckEx (INSTALL_MORE_MEMORY,
MmNumberOfPhysicalPages,
MmLowestPhysicalPage,
MmHighestPhysicalPage,
0x101);
}
5. MiReloadBootLoadedDrivers (LoaderBlock); ntldr把启动驱动放在了80000000处,现在可以开始重定位到系统pte处了
6.确定系统内存规模,建立系统缓存和系统缓存工作集
7 MiBuildPagedPool ();建立换页池
至此系统空间的定义和初始化都已经完成了,初始化了一下PsLoadedModuleList,由MiInitializeLoadedModuleList实现
1阶段:
主要工作:创建\\Device\\PhsicalMemory的内存区对象,设置MmSharedUserDataPte 使得0xffdf0000和0x7ffe0000共享内存
初始化会话空间
开启修改页面写出器
初始化内存事件
开启平衡及管理器KeBalanceSetManager KeSwapProcessOrStack两个线程
开启零化内存线程
对加载模块设置保护属性
2阶段:
设置加载模块PAGE段为可换页的