前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >windows下MmAccessFault->MiDispatchFault处理过程说明

windows下MmAccessFault->MiDispatchFault处理过程说明

原创
作者头像
kkindof
发布2019-03-28 11:15:23
1.6K0
发布2019-03-28 11:15:23
举报

页错误的时候,先处理有效的情况,例如copy-on-write

二.无效情况:

MmAccessFault函数中查看到faultaddress对应的pte无效之时,查看TempPte.u.Soft.Prototype,

1 判断原型pte 

if (TempPte.u.Soft.Prototype != 0) {

如果是指向原型PTE,就要找出对应的原型PTE

            PointerProtoPte = MiPteToProto (&TempPte); //这个是直接在PTE中取出来

            if ((SessionAddress == TRUE) &&

                (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)) {

//这个是从VAD树里面找出来

                PointerProtoPte = MiCheckVirtualAddress (VirtualAddress,

                                                         &ProtectionCode,

                                                         &ProtoVad);

  这

如果是,则获取对应的ppte做为 PointerProtoPte 

MiDispatchFault (

    IN ULONG_PTR FaultStatus,

    IN PVOID VirtualAddress,

    IN PMMPTE PointerPte,

    IN PMMPTE PointerProtoPte,

    IN LOGICAL RecheckAccess,

    IN PEPROCESS Process,

    IN PVOID TrapInformation,

    IN PMMVAD Vad

    )

最后不管什么情况,就去调用MiDispatchFault来处理page fault

下面是MiDispatchFault中的处理情况:

1。原型PTE,当PointerProtoPte不为空时,说明这是一个原型PTE,调用MiResolveProtoPteFault来处理

else TempPte = *PointerPte;

2 ,transition状态的PTE 

        else if ((TempPte.u.Soft.Transition == 0) &&

                 (TempPte.u.Soft.Protection == 0)) {

调用 MiResolveTransitionFault 来解决

3。 

        else if (TempPte.u.Soft.PageFileHigh == 0) {

            //

            // Demand zero fault.

            //

            status = MiResolveDemandZeroFault (VirtualAddress,

 4。

 else {

            //

            // Page resides in paging file.

            //

MiResolvePageFileFault

在调用 MiResolveProtoPteFault 处理原型PTE时候,也要根据判断原型PTE是否有效来处理

原型PTE有效的话,直接调用MiCompleteProtoPteFault 完成处理

否则无效时,又对应下面4种情况:

    // Make the prototype PTE valid, the prototype PTE is in

    // one of these 4 states:

    //

    //   demand zero

    //   transition

    //   paging file

    //   mapped file 

//下面的判断是按顺序来的。

//if (TempPte.u.Soft.Prototype == 1) {MiResolveMappedFileFault//这个是用subsection来读取

    // Calculate address of subsection for this prototype PTE.

    // //PointerPte里面记录的是subsection的偏移(相对MmSubsectionBase),MmSubsectionBase =MmNonPagedPoolstart

    Subsection = MiGetSubsectionAddress (PointerPte);

else if (TempPte.u.Soft.Transition == 1) {MiResolveTransitionFault //本身里面的物理页还在内存中。只是暂时无效而已

else if (TempPte.u.Soft.PageFileHigh == 0) {MiResolveDemandZeroFault//找一块物理内存,清空,然后让原来的pte有效并指向这块物理内存

else {

        //

        // Paging file.

        //

  ////TempPte.u.Soft.PageFileHigh便是在page中的偏移,但只有20位,这是页编号,按页对齐,所以//TempPte.u.Soft.PageFileHigh<<12后才是准确的offset

//所以pagefile最大也是只支持4G,windows internals这书里面也有提到

        status = MiResolvePageFileFault (FaultingAddress,

                                         PointerProtoPte,  

    //

 //////////////////////////////////////

在处理有效的原型PTE时调用MiCompleteProtoPteFault。

里面只使用了PointerProtoPte原型PTE获取对应的PageFrameIndex,然后就设置给相应的va的pte,

        MI_MAKE_VALID_USER_PTE (TempPte,

                                PageFrameIndex,

                                Protection,

                                PointerPte);

PageFrameIndex并不是从pfn的"原始PTE内容:"取的

无效原型PTE时,也只是从原型PTE获取Subsection,并不是用了pfn中的原始内容,这里和书上说的有出入。奇怪

。有了subsection后,就能能进来了

    //

    // Calculate address of subsection for this prototype PTE.

    //

    Subsection = MiGetSubsectionAddress (PointerPte);

================================================

另外,这里也有一个地方说明了不要在dispatch level下访问分页内存的原因:

     // Issue the read request.

        //

        status = IoPageRead (ReadBlock->FilePointer,

                             &ReadBlock->Mdl,

                             &ReadBlock->ReadOffset,

                             &ReadBlock->Event,

                             &ReadBlock->IoStatus);

        if (!NT_SUCCESS(status)) {

            //

            // Set the event as the I/O system doesn't set it on errors.

            //

            ReadBlock->IoStatus.Status = status;

            ReadBlock->IoStatus.Information = 0;

            KeSetEvent (&ReadBlock->Event, 0, FALSE);

        }

        //

        // Initializing PageFrameIndex is not needed for correctness, but

        // without it the compiler cannot compile this code W4 to check

        // for use of uninitialized variables.

        //

        PageFrameIndex = (PFN_NUMBER)-1;

        //

        // Wait for the I/O operation.

        //

        status = MiWaitForInPageComplete (ReadBlock->Pfn,

                                          ReadPte,

                                          VirtualAddress,

                                          &OriginalPte,

                                          CapturedEvent,

                                          Process);

注:CapturedEvent和ReadBlock是同一块内存来的,

ChildEBP RetAddr  

f7556358 8084bc13 nt!MiWaitForInPageComplete+0xd [c:\wrk-v1.2\base\ntos\mm\pagfault.c @ 4174]

f75563e0 80856fda nt!MiDispatchFault+0xd57 [c:\wrk-v1.2\base\ntos\mm\pagfault.c @ 1271]

f755643c 808858d8 nt!MmAccessFault+0x9c0 [c:\wrk-v1.2\base\ntos\mm\mmfault.c @ 2001]

f755643c 75de7c8b nt!_KiTrap0E+0xdc [C:\WRK-v1.2\base\ntos\ke\i386\trap.asm @ 5527]

0129f508 75db67b5 BROWSEUI!LoadToolbarBackBmp+0xf4

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档