3.1.3 看对于“肮脏”页面的处理

3.1.3 看对于“肮脏”页面的处理


再看对于“肮脏”页面的处理

MmPageOutVirtualMemory()


NTSTATUS
NTAPI
MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
                       PMEMORY_AREA MemoryArea,
                       PVOID Address,
                       PMM_PAGEOP PageOp)
{
   PFN_TYPE Page;
   BOOLEAN WasDirty;
   SWAPENTRY SwapEntry;
   NTSTATUS Status;

   DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
          Address, AddressSpace->Process->UniqueProcessId);

   /*
    * Check for paging out from a deleted virtual memory area.
    */
   if (MemoryArea->DeleteInProgress)
   {
      PageOp->Status = STATUS_UNSUCCESSFUL;
      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
      MmReleasePageOp(PageOp);
      return(STATUS_UNSUCCESSFUL);
   }

   /*
    * Disable the virtual mapping.
    */
   MmDisableVirtualMapping(AddressSpace->Process, Address,
                           &WasDirty, &Page);

   if (Page == 0)
   {
      KEBUGCHECK(0);
   }

   /*
    * Paging out non-dirty data is easy.
    */
   if (!WasDirty)
   {
      MmLockAddressSpace(AddressSpace);
      MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);
      MmDeleteAllRmaps(Page, NULL, NULL);
      if ((SwapEntry = MmGetSavedSwapEntryPage(Page)) != 0)
      {
         MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);
         MmSetSavedSwapEntryPage(Page, 0);
      }
      MmUnlockAddressSpace(AddressSpace);
      MmReleasePageMemoryConsumer(MC_USER, Page);
      PageOp->Status = STATUS_SUCCESS;
      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
      MmReleasePageOp(PageOp);
      return(STATUS_SUCCESS);
   }

   /*
    * If necessary, allocate an entry in the paging file for this page
    */
   SwapEntry = MmGetSavedSwapEntryPage(Page);//获取该物理页面的倒换描述项
   //页面是脏的
   if (SwapEntry == 0)//分配失败
   {
      SwapEntry = MmAllocSwapPage();
      if (SwapEntry == 0)
      {
         MmShowOutOfSpaceMessagePagingFile();
         MmEnableVirtualMapping(AddressSpace->Process, Address);//恢复原来的映射
         PageOp->Status = STATUS_UNSUCCESSFUL;
         KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
         MmReleasePageOp(PageOp);
         return(STATUS_PAGEFILE_QUOTA);//因倒换页面不够而失败
      }
   }

   /*
    * Write the page to the pagefile
    */
   Status = MmWriteToSwapPage(SwapEntry, Page);//将物理页面的内容写入倒换页面
   if (!NT_SUCCESS(Status))
   {//写文件失败
      DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
              Status);
      MmEnableVirtualMapping(AddressSpace->Process, Address);//恢复原来的映射
      PageOp->Status = STATUS_UNSUCCESSFUL;
      KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
      MmReleasePageOp(PageOp);
      return(STATUS_UNSUCCESSFUL);
   }

   /*
    * Otherwise we have succeeded, free the page1 写倒换文件成功
    */
   DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page << PAGE_SHIFT);
   MmLockAddressSpace(AddressSpace);
   MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, NULL, NULL);//撤销通往目标物理页面的映射
   MmCreatePageFileMapping(AddressSpace->Process, Address, SwapEntry);//建立(虚存页面)通往倒换文件的映射
   MmUnlockAddressSpace(AddressSpace);
   MmDeleteAllRmaps(Page, NULL, NULL);
   MmSetSavedSwapEntryPage(Page, 0);//该物理页面不再映射到倒换文件
   MmReleasePageMemoryConsumer(MC_USER, Page);//释放该物理页面
   PageOp->Status = STATUS_SUCCESS;
   KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
   MmReleasePageOp(PageOp);
   return(STATUS_SUCCESS);
}

先通过 MmGetSavedSwapEntryPage()获取(本页面)在页面倒换文件中的页面号。如果本页面在倒换文件中尚无映像,就通过MmAllocSwapPage()加以分配。然后就由MmWriteToSwapPage()将物理页面的内容写入倒换文件。此后的操作就无须赘述了,不过需要说明一点,就是MmCreatePageFileMapping()在将SwapEntry写入相应虚存页面的PTE,时要将其左移一位,使得PTE的最低位即PA_PRESENT位为0,说明该页面不在物理内存中。在哪里呢?只要整个PTE非0,就说明在某个倒换文件的某个页面中,此时的高31位就是倒换文件号与页面号的组合。显然,这个组合不能为0,这就是为什么这个组合中的页面号实际上是(文件内)页面号加1的原因。
关于页面映射表,还要作些说明。当内核调度一个进程运行时,需要将控制寄存器CR3设置成指向这个进程的页面映射表,此时使用的是页面映射表的物理地址,这样MMU才能找到当前进程的页面映射表,并进而将具体的表项PTE装入其高速缓存TLB。但是,如果是CPU要访问当前进程的页面映射表,则需使用其虚拟地址。不管是什么进程,其页面映射表在虚存空间的位置都是固定的,都是 0xc0000000。凡是在程序中需要访问本进程的页面映射表时,总是用这个地址作为起点。当然,对于不同的当前进程,这个虚拟地址会映射到不同的物理页面中,不同进程的页面映射表所在的物理页面当然是不同的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值