对无效页面的一次访问称为“缺页错误”。对于这类错误都会导致中断处理函数MmAccessFault。那么什么样的情况才叫做无效页面呢?主要有下面几种情况:
l 所有访问的页面不存内存里,而是磁盘里。
l 访问的页面在后备列表里。
l 访问的页面没有提交写操作。
l 对只读页面产生写操作。
l 非法访问其它进程的页面。
可见,缺页中断处理函数不仅要处理大部份换页的情况,还需要处理非法访问其它页面的情况,因此这个函数的代码也是很复杂的。现在就来分析函数的代码,如下:
#001 NTSTATUS
#002 NTAPI
#003 MmAccessFault(IN BOOLEAN StoreInstruction,
#004 IN PVOID Address,
#005 IN KPROCESSOR_MODE Mode,
#006 IN PVOID TrapInformation)
#007 {
这个函数里的几个参数是什么意呢?
StoreInstruction是一个布尔值,表示缺页的情况是否是储存数据时,数据还没有提交的写操作出错。如果这个值为假,说明这是页面不存在或者不允许读取时产生的错误。
Address是访问出错时的页面线性地址。
TrapInformation是指是否提供TRAP信息。
下面对内核内存页面处理优化。
#008 /* Cute little hack for ROS */
#009 if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
#010 {
#011 #ifdef _M_IX86
检查非法的页面是否在内核里面。
#012 /* Check for an invalid page directory in kernel mode */
#013 if (Mmi386MakeKernelPageTableGlobal(Address))
#014 {
如果在内核目录内,就返回成功。
#015 /* All is well with the world */
#016 return STATUS_SUCCESS;
#017 }
#018 #endif
#019 }
#020
如果写数据时出错,就调用函数MmpAccessFault来处理写页面出错处理。
#021 /* Keep same old ReactOS BehavIoUr */
#022 if (StoreInstruction)
#023 {
#024 /* Call access fault */
#025 return MmpAccessFault(Mode,(ULONG_PTR)Address,TrapInformation ? FALSE : TRUE);
#026 }
#027 else
#028 {
如果是读取页面出错,就调用函数MmNotPresentFault来处理缺页中断处理。
#029 /* Call not present */
#030 return MmNotPresentFault(Mode,TrapInformation ? FALSE : TRUE);
#031 }
#032 }
#033
通过上面的函数分析,先作内核页面优化,然后把缺页中断分成读取页面中断和写页页中断,然后再调具体的函数去处理更详细的内容。