#001 NTSTATUS
#002 NTAPI
#003 MmpAccessFault(KPROCESSOR_MODE Mode,
#004 ULONG_PTR Address,
#005 BOOLEAN FromMdl)
#006 {
#007 PMM_AVL_TABLE AddressSpace;
#008 MEMORY_AREA* MemoryArea;
#009 NTSTATUS Status;
#010 BOOLEAN Locked = FromMdl;
#011
调试输出。
#012 DPRINT("MmAccessFault(Mode %d,Address %x)/n",Mode,Address);
#013
判断请求优先级是否大于DISPATCH_LEVEL级别,如果大于这个级别,就需要不能进行缺页处理。
#014 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
#015 {
#016 DPRINT1("Page fault at high IRQL was %d/n",KeGetCurrentIrql());
#017 return(STATUS_UNSUCCESSFUL);
#018 }
判断当前进程是否为空。
#019 if (PsGetCurrentProcess() == NULL)
#020 {
#021 DPRINT("No current process/n");
#022 return(STATUS_UNSUCCESSFUL);
#023 }
#024
通过缺页中断的内存地址找到内存块。
#025 /*
#026 * Find the memory area for the faulting address
#027 */
#028 if (Address >= (ULONG_PTR)MmSystemRangeStart)
#029 {
如果是内存地址在系统范围内存里,就需要检查是否在内核模式下访问,否则在用户状态下访问是非法的。
#030 /*
#031 * Check permissions
#032 */
#033 if (Mode != KernelMode)
#034 {
#035 DPRINT1("MmAccessFault(Mode %d,Address);
#036 return(STATUS_ACCESS_VIOLATION);
#037 }
#038 AddressSpace = MmGetKernelAddressSpace();
#039 }
#040 else
#041 {
#042 AddressSpace = &PsGetCurrentProcess()->VadRoot;
#043 }
#044
判断是否需要锁住内存。
#045 if (!FromMdl)
#046 {
#047 MmLockAddressSpace(AddressSpace);
#048 }
从所在内存空间里找到内存块。
#049 do
#050 {
#051 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,(PVOID)Address);
#052 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
#053 {
#054 if (!FromMdl)
#055 {
#056 MmUnlockAddressSpace(AddressSpace);
#057 }
这里返回非法访问的内存。
#058 return (STATUS_ACCESS_VIOLATION);
#059 }
#060
#061 switch (MemoryArea->Type)
#062 {
系统内存非法访问。
#063 case MEMORY_AREA_SYSTEM:
#064 Status = STATUS_ACCESS_VIOLATION;
#065 break;
#066
内存已经放分页缓存。
#067 case MEMORY_AREA_PAGED_POOL:
#068 Status = STATUS_SUCCESS;
#069 break;
#070
这里就找到相应的内存块。
#071 case MEMORY_AREA_SECTION_VIEW:
#072 Status = MmAccessFaultSectionView(AddressSpace,
#073 MemoryArea,
#074 (PVOID)Address,
#075 Locked);
#076 break;
#077
虚拟内存非法访问
#078 case MEMORY_AREA_VIRTUAL_MEMORY:
#079 Status = STATUS_ACCESS_VIOLATION;
#080 break;
#081
共享内存非法访问。
#082 case MEMORY_AREA_SHARED_DATA:
#083 Status = STATUS_ACCESS_VIOLATION;
#084 break;
#085
缺省都是返回非法访问内存。
#086 default:
#087 Status = STATUS_ACCESS_VIOLATION;
#088 break;
#089 }
#090 }
#091 while (Status == STATUS_MM_RESTART_OPERATION);
#092
查找到内存块完成,并进行内存解锁操作。
#093 DPRINT("Completed page fault handling/n");
#094 if (!FromMdl)
#095 {
#096 MmUnlockAddressSpace(AddressSpace);
#097 }
#098 return(Status);
#099 }
上面这个函数,先判断缺页内存地址在系统空间,还是在用户空间,然后再在相应的空间里查找地址所有内存块。如果找到内存,就在函数MmAccessFaultSectionView里处理相应的功能。