-
-
[讨论]WRK1.2中断处理中MiResolveMappedFileFault函数试读
-
发表于: 2009-3-13 10:39 4750
-
/*
菜鸟路过~~
额是菜鸟,大家预备好板砖,狠狠砸~~牛人看过此文,切记莫笑掉大牙~
发此贴主要是同诸位交流,还有很多不甚明白的地方,已标注,还望大家不吝赐教!
读了MiResolveMappedFileFault函数,是页面中断出错时调用的一个子程序,
参数PointerPte是出错的PTE,注意这是一个原型PTE
MiResolveMappedFileFault函数的主要作用是根据Process和Controlarea以及系统情况来得到
应从文件的何处读,并且设好PFN。参考资料是解析Winndows 2000/XP物理内存管理等文
*/
NTSTATUS
MiResolveMappedFileFault (
IN PMMPTE PointerPte,
OUT PMMINPAGE_SUPPORT *ReadBlock,
IN PEPROCESS Process,
IN KIRQL OldIrql
)
/*++
Routine Description:
This routine builds the MDL and other structures to allow a
read operation on a mapped file for a page fault.
Arguments:
PointerPte - Supplies the PTE for the faulting address.
ReadBlock - Supplies a pointer to put the address of the read block which
needs to be completed before an I/O can be issued.
Process - Supplies a pointer to the process object. If this
parameter is NULL, then the fault is for system
space and the process's working set lock is not held.
OldIrql - Supplies the IRQL the caller acquired the PFN lock at.
Return Value:
status. A status value of STATUS_ISSUE_PAGING_IO is returned
if this function completes successfully.
Environment:
Kernel mode, PFN lock held.
--*/
{
PFN_NUMBER PageFrameIndex;
PMMPFN Pfn1;
PSUBSECTION Subsection;
PCONTROL_AREA ControlArea;
PMDL Mdl;
ULONG ReadSize;
PETHREAD CurrentThread;
PPFN_NUMBER Page;
PPFN_NUMBER EndPage;
PMMPTE BasePte;
PMMPTE CheckPte;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER TempOffset;
PPFN_NUMBER FirstMdlPage;
PMMINPAGE_SUPPORT ReadBlockLocal;
ULONG PageColor;
ULONG ClusterSize;
PFN_NUMBER AvailablePages;
NTSTATUS Status;
PKPRCB Prcb;
ClusterSize = 0;
ASSERT (PointerPte->u.Soft.Prototype == 1);
// *********************************************
// Mapped File (subsection format)
// *********************************************
if ((MmAvailablePages < MM_HIGH_LIMIT) &&
(MiEnsureAvailablePageOrWait (Process, OldIrql))) {
//
// A wait operation was performed which dropped the locks,
// repeat this fault.
//
return STATUS_REFAULT;
}
//
// Calculate address of subsection for this prototype PTE.
//这是个原型PTE。由此可以得到相应的subsection
//MiGetSubsectionAddress是一个宏。在mi.h中
Subsection = MiGetSubsectionAddress (PointerPte);
ControlArea = Subsection->ControlArea;
//该区不可更改
if (ControlArea->u.Flags.FailAllIo) {
return STATUS_IN_PAGE_ERROR;
}
//
//这里可以进行判断,PointerPte是否是超出Subsection的范围
//Subsection->SubsectionBase是该Subsection的原型PTE表的首地址,
//&Subsection->SubsectionBase[Subsection->PtesInSubsection]为末地址
//数组飘过~~
if (PointerPte >= &Subsection->SubsectionBase[Subsection->PtesInSubsection]) {
//
// Attempt to read past the end of this subsection.
//返回,访问违例
return STATUS_ACCESS_VIOLATION;
}
ASSERT (ControlArea->u.Flags.Rom != 1);
//
//ReadBlockLocal是指向MMINPAGE_SUPPORT结构的。MI.H中有其定义。
//用来告诉调用者将来从映射文件中的何处偏移开始读,读多少,存入
//到哪里等等
CurrentThread = PsGetCurrentThread ();
ReadBlockLocal = MiGetInPageSupportBlock (OldIrql, &Status);
if (ReadBlockLocal == NULL) {
ASSERT (!NT_SUCCESS (Status));
return Status;
}
*ReadBlock = ReadBlockLocal;
//
// Build an MDL for the request.
//
Mdl = &ReadBlockLocal->Mdl;
//PFN_NUMBER Page[MM_MAXIMUM_READ_CLUSTER_SIZE + 1]
//实际上就是该数组的指针
FirstMdlPage = &ReadBlockLocal->Page[0];
//
//page在下面很重要
Page = FirstMdlPage;
#if DBG
RtlFillMemoryUlong (Page, (MM_MAXIMUM_READ_CLUSTER_SIZE+1) * sizeof(PFN_NUMBER), 0xf1f1f1f1);
#endif //DBG
//
//请诸位想PointerPte是原型PTE页面表中的一项。
//
ReadSize = PAGE_SIZE;
BasePte = PointerPte;
//
// Should we attempt to perform page fault clustering?
//
AvailablePages = MmAvailablePages;
//额 ~~~汗,这里没看懂,抛砖引玉
if (MiInPageSinglePages != 0) {
AvailablePages = 0;
MiInPageSinglePages -= 1;
}
//如果当前线程允许预读(我是这样理解的,应该是)当前线程可以预读页面,
//同时当前控制区可以修改
if ((!CurrentThread->DisablePageFaultClustering) &&
(ControlArea->u.Flags.NoModifiedWriting == 0)) {
if ((AvailablePages > (MmFreeGoal * 2))
||
(((ControlArea->u.Flags.Image != 0) ||
(CurrentThread->ForwardClusterOnly)) &&
(AvailablePages > MM_HIGH_LIMIT))) {
//
// Cluster up to n pages. This one + n-1.
//
ASSERT (MM_HIGH_LIMIT > MM_MAXIMUM_READ_CLUSTER_SIZE + 16);
ASSERT (AvailablePages > MM_MAXIMUM_READ_CLUSTER_SIZE + 16);
//
//在这种情况下,可以cluster read,那么就要根据control area
//是Image类型的还是Data类型的,设置ClusterSize.
//什么样子的类型,通过file_object->_SECTION_OBJECT_POINTERS
//该项查看
if (ControlArea->u.Flags.Image == 0) {
ASSERT (CurrentThread->ReadClusterSize <=
MM_MAXIMUM_READ_CLUSTER_SIZE);
ClusterSize = CurrentThread->ReadClusterSize;
}
else {
ClusterSize = MmDataClusterSize;
if (Subsection->u.SubsectionFlags.Protection &
MM_PROTECTION_EXECUTE_MASK ) {
ClusterSize = MmCodeClusterSize;
}
}
//以上几句是根据控制区和线程的设置来得到ClusterSize的大小
//
//ReadBlockLocal下的那个PFN_NUMBER Page[MM_MAXIMUM_READ_CLUSTER_SIZE + 1]
//EndPage指向第ClusterSize元素
EndPage = Page + ClusterSize;
//
//
//指向下一个的PTE
CheckPte = PointerPte + 1;
//
// Try to cluster within the page of PTEs.
//在PTE页面中集中使用。
//指的是说,CheckPTE在PTE页面中
//#define MiIsPteOnPdeBoundary(PTE) (((ULONG_PTR)(PTE) & (PAGE_SIZE - 1)) == 0)
//Page < EndPage根据ClusterSize设置
//CheckPte <
// &Subsection->SubsectionBase[Subsection->PtesInSubsection]
//是CheckPte莫要超过subsection的区间
//再下一个,额猜是页面属性相同
while ((MiIsPteOnPdeBoundary(CheckPte) == 0) &&
(Page < EndPage) &&
(CheckPte <
&Subsection->SubsectionBase[Subsection->PtesInSubsection])
&& (CheckPte->u.Long == BasePte->u.Long)) {
ControlArea->NumberOfPfnReferences += 1;
ReadSize += PAGE_SIZE;
Page += 1;
CheckPte += 1;
}
//CheckPte起到游标的作用
//看看当前线程允许往前集中么
if ((Page < EndPage) && (!CurrentThread->ForwardClusterOnly)) {
//
// Attempt to cluster going backwards from the PTE.
//
CheckPte = PointerPte - 1;
//第一个判断是什么意思?
while ((((ULONG_PTR)CheckPte & (PAGE_SIZE - 1)) !=
(PAGE_SIZE - sizeof(MMPTE))) &&
(Page < EndPage) &&
(CheckPte >= Subsection->SubsectionBase) &&
(CheckPte->u.Long == BasePte->u.Long)) {
ControlArea->NumberOfPfnReferences += 1;
ReadSize += PAGE_SIZE;
Page += 1;
CheckPte -= 1;
}
BasePte = CheckPte + 1;
//BasePte得到的是Subsection可以从映射文件读的第一个PTE。
//
}
}
}
//
//
// Calculate the offset to read into the file.
// offset = base + ((thispte - basepte) << PAGE_SHIFT)
//base是该Subsection得到的分区的及地址,然后加上原来的
//Subsection的偏移。MiStartingOffset很重要。见文末。
StartingOffset.QuadPart = MiStartingOffset (Subsection, BasePte);
TempOffset = MiEndingOffset (Subsection);
ASSERT (StartingOffset.QuadPart < TempOffset.QuadPart);
//
// Remove pages to fill in the MDL. This is done here as the
// base PTE has been determined and can be used for virtual
// aliasing(混淆现象) checks.
//Page是Subsection页面的终结,BasePte是最底层的那个PTE
EndPage = FirstMdlPage;
CheckPte = BasePte;
//
//卖糕的,额不知道下面是什么意思,只知道取得页帧,
//将其给page,就是那个老是提到的数组。
//什么是PageColor?
while (EndPage < Page) {
if (Process == HYDRA_PROCESS) {
PageColor = MI_GET_PAGE_COLOR_FROM_SESSION (MmSessionSpace);
}
else if (Process == NULL) {
PageColor = MI_GET_PAGE_COLOR_FROM_PTE (CheckPte);
}
else {
PageColor = MI_PAGE_COLOR_PTE_PROCESS (CheckPte,
&Process->NextPageColor);
}
*EndPage = MiRemoveAnyPage (PageColor);
EndPage += 1;
CheckPte += 1;
}
if (Process == HYDRA_PROCESS) {
PageColor = MI_GET_PAGE_COLOR_FROM_SESSION (MmSessionSpace);
}
else if (Process == NULL) {
PageColor = MI_GET_PAGE_COLOR_FROM_PTE (CheckPte);
}
else {
PageColor = MI_PAGE_COLOR_PTE_PROCESS (CheckPte,
&Process->NextPageColor);
}
//
// Check to see if the read will go past the end of the file,
// If so, correct the read size and get a zeroed page.
//
Prcb = KeGetCurrentPrcb ();
InterlockedIncrement (&Prcb->MmPageReadIoCount);
InterlockedExchangeAdd (&Prcb->MmPageReadCount,
(LONG) (ReadSize >> PAGE_SHIFT));
//如果控制区是可执行文件的映像,并且超过文件的大小,那么重新设定读的大小
//从这里来看, 貌似是一个subsection对应一个文件对象
//
if ((ControlArea->u.Flags.Image) &&
(((UINT64)StartingOffset.QuadPart + ReadSize) > (UINT64)TempOffset.QuadPart)) {
ASSERT ((ULONG)(TempOffset.QuadPart - StartingOffset.QuadPart)
> (ReadSize - PAGE_SIZE));
ReadSize = (ULONG)(TempOffset.QuadPart - StartingOffset.QuadPart);
//
// Round the offset to a 512-byte offset as this will help filesystems
// optimize the transfer. Note that filesystems will always zero fill
// the remainder between VDL and the next 512-byte multiple and we have
// already zeroed the whole page.
//
ReadSize = ((ReadSize + MMSECTOR_MASK) & ~MMSECTOR_MASK);
PageFrameIndex = MiRemoveZeroPage (PageColor);
}
else {
//
// We are reading a complete page, no need to get a zeroed page.
//
PageFrameIndex = MiRemoveAnyPage (PageColor);
}
//
// Increment the PFN reference count in the control area for
// the subsection (the PFN lock is required to modify this field).
//
ControlArea->NumberOfPfnReferences += 1;
//现在才赋值page,
//page最早是赋值FirstMdlPage的,后来根据Clustersize和其他来不断增加。
*Page = PageFrameIndex;
//
//这里FirstMdlPage还是那个数组的起始地址,PointerPte是
//出错的PTE地址,BasePte是PointerPte下面的那个PTE
//由代码来看的话,应当是ReadBlockLocal的PFN_NUMBER Page[MM_MAXIMUM_READ_CLUSTER_SIZE + 1]
//元素应该已经有了PageFrameIndex了。不知这样理解正确否?
PageFrameIndex = *(FirstMdlPage + (PointerPte - BasePte));
//
// Get a page and put the PTE into the transition state with the
// read-in-progress flag set.
//
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
//
// Initialize MDL for request.
//初始化MDL
MmInitializeMdl (Mdl,
MiGetVirtualAddressMappedByPte (BasePte),
ReadSize);
Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
#if DBG
if (ReadSize > ((ClusterSize + 1) << PAGE_SHIFT)) {
KeBugCheckEx (MEMORY_MANAGEMENT, 0x777,(ULONG_PTR)Mdl, (ULONG_PTR)Subsection,
(ULONG)TempOffset.LowPart);
}
#endif //DBG
//这个没看,应当是设置读时的,PFN设置问题,防止他用
MiInitializeReadInProgressPfn (Mdl,
BasePte,
&ReadBlockLocal->Event,
MI_PROTOTYPE_WSINDEX);
MI_ZERO_USED_PAGETABLE_ENTRIES_IN_INPAGE_SUPPORT(ReadBlockLocal);
ReadBlockLocal->ReadOffset = StartingOffset;
ReadBlockLocal->FilePointer = ControlArea->FilePointer;
ReadBlockLocal->BasePte = BasePte;
ReadBlockLocal->Pfn = Pfn1;
return STATUS_ISSUE_PAGING_IO;
}
LONGLONG
FORCEINLINE
MiStartingOffset (
IN PSUBSECTION Subsection,
IN PMMPTE PteAddress
)
/*++
Routine Description:
This function calculates the file offset given a subsection and a PTE
offset. Note that images are stored in 512-byte units whereas data is
stored in 4K units.
Arguments:
Subsection - Supplies a subsection to reference for the file address.
PteAddress - Supplies a PTE within the subsection
Return Value:
Returns the file offset to obtain the backing data from.
MiStartingOffset (Subsection, BasePte);这是在ResolveMappedFile中的调用
--*/
{
LONGLONG PteByteOffset;
LARGE_INTEGER StartAddress;
//如果该subsection指向的是可执行文件映像
//
if (Subsection->ControlArea->u.Flags.Image == 1) {
return MI_STARTING_OFFSET (Subsection, PteAddress);
}
ASSERT (Subsection->SubsectionBase != NULL);
//得到要读入的字节大小
PteByteOffset = (LONGLONG)((PteAddress - Subsection->SubsectionBase))
<< PAGE_SHIFT;
/*
#define Mi4KStartFromSubsection(address, subsection) \
((PLARGE_INTEGER)address)->LowPart = subsection->StartingSector; \
((PLARGE_INTEGER)address)->HighPart = subsection->u.SubsectionFlags.StartingSector4132;
MM4K_SHIFT 12
*/
//Mi4KStartFromSubsection得到的是该subsection在
//映射文件中的偏移,但是subsection->StartingSector
//让我产生的疑惑是难道用到的是扇区?
//但是从紧接着的一句来看,又貌似是文件中的绝对位移~
//faint,哪位大侠帮帮忙?
Mi4KStartFromSubsection (&StartAddress, Subsection);
StartAddress.QuadPart = StartAddress.QuadPart << MM4K_SHIFT;
//可以一次性读出的大小+文件已有的偏移
PteByteOffset += StartAddress.QuadPart;
return PteByteOffset;
}
菜鸟路过~~
额是菜鸟,大家预备好板砖,狠狠砸~~牛人看过此文,切记莫笑掉大牙~
发此贴主要是同诸位交流,还有很多不甚明白的地方,已标注,还望大家不吝赐教!
读了MiResolveMappedFileFault函数,是页面中断出错时调用的一个子程序,
参数PointerPte是出错的PTE,注意这是一个原型PTE
MiResolveMappedFileFault函数的主要作用是根据Process和Controlarea以及系统情况来得到
应从文件的何处读,并且设好PFN。参考资料是解析Winndows 2000/XP物理内存管理等文
*/
NTSTATUS
MiResolveMappedFileFault (
IN PMMPTE PointerPte,
OUT PMMINPAGE_SUPPORT *ReadBlock,
IN PEPROCESS Process,
IN KIRQL OldIrql
)
/*++
Routine Description:
This routine builds the MDL and other structures to allow a
read operation on a mapped file for a page fault.
Arguments:
PointerPte - Supplies the PTE for the faulting address.
ReadBlock - Supplies a pointer to put the address of the read block which
needs to be completed before an I/O can be issued.
Process - Supplies a pointer to the process object. If this
parameter is NULL, then the fault is for system
space and the process's working set lock is not held.
OldIrql - Supplies the IRQL the caller acquired the PFN lock at.
Return Value:
status. A status value of STATUS_ISSUE_PAGING_IO is returned
if this function completes successfully.
Environment:
Kernel mode, PFN lock held.
--*/
{
PFN_NUMBER PageFrameIndex;
PMMPFN Pfn1;
PSUBSECTION Subsection;
PCONTROL_AREA ControlArea;
PMDL Mdl;
ULONG ReadSize;
PETHREAD CurrentThread;
PPFN_NUMBER Page;
PPFN_NUMBER EndPage;
PMMPTE BasePte;
PMMPTE CheckPte;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER TempOffset;
PPFN_NUMBER FirstMdlPage;
PMMINPAGE_SUPPORT ReadBlockLocal;
ULONG PageColor;
ULONG ClusterSize;
PFN_NUMBER AvailablePages;
NTSTATUS Status;
PKPRCB Prcb;
ClusterSize = 0;
ASSERT (PointerPte->u.Soft.Prototype == 1);
// *********************************************
// Mapped File (subsection format)
// *********************************************
if ((MmAvailablePages < MM_HIGH_LIMIT) &&
(MiEnsureAvailablePageOrWait (Process, OldIrql))) {
//
// A wait operation was performed which dropped the locks,
// repeat this fault.
//
return STATUS_REFAULT;
}
//
// Calculate address of subsection for this prototype PTE.
//这是个原型PTE。由此可以得到相应的subsection
//MiGetSubsectionAddress是一个宏。在mi.h中
Subsection = MiGetSubsectionAddress (PointerPte);
ControlArea = Subsection->ControlArea;
//该区不可更改
if (ControlArea->u.Flags.FailAllIo) {
return STATUS_IN_PAGE_ERROR;
}
//
//这里可以进行判断,PointerPte是否是超出Subsection的范围
//Subsection->SubsectionBase是该Subsection的原型PTE表的首地址,
//&Subsection->SubsectionBase[Subsection->PtesInSubsection]为末地址
//数组飘过~~
if (PointerPte >= &Subsection->SubsectionBase[Subsection->PtesInSubsection]) {
//
// Attempt to read past the end of this subsection.
//返回,访问违例
return STATUS_ACCESS_VIOLATION;
}
ASSERT (ControlArea->u.Flags.Rom != 1);
//
//ReadBlockLocal是指向MMINPAGE_SUPPORT结构的。MI.H中有其定义。
//用来告诉调用者将来从映射文件中的何处偏移开始读,读多少,存入
//到哪里等等
CurrentThread = PsGetCurrentThread ();
ReadBlockLocal = MiGetInPageSupportBlock (OldIrql, &Status);
if (ReadBlockLocal == NULL) {
ASSERT (!NT_SUCCESS (Status));
return Status;
}
*ReadBlock = ReadBlockLocal;
//
// Build an MDL for the request.
//
Mdl = &ReadBlockLocal->Mdl;
//PFN_NUMBER Page[MM_MAXIMUM_READ_CLUSTER_SIZE + 1]
//实际上就是该数组的指针
FirstMdlPage = &ReadBlockLocal->Page[0];
//
//page在下面很重要
Page = FirstMdlPage;
#if DBG
RtlFillMemoryUlong (Page, (MM_MAXIMUM_READ_CLUSTER_SIZE+1) * sizeof(PFN_NUMBER), 0xf1f1f1f1);
#endif //DBG
//
//请诸位想PointerPte是原型PTE页面表中的一项。
//
ReadSize = PAGE_SIZE;
BasePte = PointerPte;
//
// Should we attempt to perform page fault clustering?
//
AvailablePages = MmAvailablePages;
//额 ~~~汗,这里没看懂,抛砖引玉
if (MiInPageSinglePages != 0) {
AvailablePages = 0;
MiInPageSinglePages -= 1;
}
//如果当前线程允许预读(我是这样理解的,应该是)当前线程可以预读页面,
//同时当前控制区可以修改
if ((!CurrentThread->DisablePageFaultClustering) &&
(ControlArea->u.Flags.NoModifiedWriting == 0)) {
if ((AvailablePages > (MmFreeGoal * 2))
||
(((ControlArea->u.Flags.Image != 0) ||
(CurrentThread->ForwardClusterOnly)) &&
(AvailablePages > MM_HIGH_LIMIT))) {
//
// Cluster up to n pages. This one + n-1.
//
ASSERT (MM_HIGH_LIMIT > MM_MAXIMUM_READ_CLUSTER_SIZE + 16);
ASSERT (AvailablePages > MM_MAXIMUM_READ_CLUSTER_SIZE + 16);
//
//在这种情况下,可以cluster read,那么就要根据control area
//是Image类型的还是Data类型的,设置ClusterSize.
//什么样子的类型,通过file_object->_SECTION_OBJECT_POINTERS
//该项查看
if (ControlArea->u.Flags.Image == 0) {
ASSERT (CurrentThread->ReadClusterSize <=
MM_MAXIMUM_READ_CLUSTER_SIZE);
ClusterSize = CurrentThread->ReadClusterSize;
}
else {
ClusterSize = MmDataClusterSize;
if (Subsection->u.SubsectionFlags.Protection &
MM_PROTECTION_EXECUTE_MASK ) {
ClusterSize = MmCodeClusterSize;
}
}
//以上几句是根据控制区和线程的设置来得到ClusterSize的大小
//
//ReadBlockLocal下的那个PFN_NUMBER Page[MM_MAXIMUM_READ_CLUSTER_SIZE + 1]
//EndPage指向第ClusterSize元素
EndPage = Page + ClusterSize;
//
//
//指向下一个的PTE
CheckPte = PointerPte + 1;
//
// Try to cluster within the page of PTEs.
//在PTE页面中集中使用。
//指的是说,CheckPTE在PTE页面中
//#define MiIsPteOnPdeBoundary(PTE) (((ULONG_PTR)(PTE) & (PAGE_SIZE - 1)) == 0)
//Page < EndPage根据ClusterSize设置
//CheckPte <
// &Subsection->SubsectionBase[Subsection->PtesInSubsection]
//是CheckPte莫要超过subsection的区间
//再下一个,额猜是页面属性相同
while ((MiIsPteOnPdeBoundary(CheckPte) == 0) &&
(Page < EndPage) &&
(CheckPte <
&Subsection->SubsectionBase[Subsection->PtesInSubsection])
&& (CheckPte->u.Long == BasePte->u.Long)) {
ControlArea->NumberOfPfnReferences += 1;
ReadSize += PAGE_SIZE;
Page += 1;
CheckPte += 1;
}
//CheckPte起到游标的作用
//看看当前线程允许往前集中么
if ((Page < EndPage) && (!CurrentThread->ForwardClusterOnly)) {
//
// Attempt to cluster going backwards from the PTE.
//
CheckPte = PointerPte - 1;
//第一个判断是什么意思?
while ((((ULONG_PTR)CheckPte & (PAGE_SIZE - 1)) !=
(PAGE_SIZE - sizeof(MMPTE))) &&
(Page < EndPage) &&
(CheckPte >= Subsection->SubsectionBase) &&
(CheckPte->u.Long == BasePte->u.Long)) {
ControlArea->NumberOfPfnReferences += 1;
ReadSize += PAGE_SIZE;
Page += 1;
CheckPte -= 1;
}
BasePte = CheckPte + 1;
//BasePte得到的是Subsection可以从映射文件读的第一个PTE。
//
}
}
}
//
//
// Calculate the offset to read into the file.
// offset = base + ((thispte - basepte) << PAGE_SHIFT)
//base是该Subsection得到的分区的及地址,然后加上原来的
//Subsection的偏移。MiStartingOffset很重要。见文末。
StartingOffset.QuadPart = MiStartingOffset (Subsection, BasePte);
TempOffset = MiEndingOffset (Subsection);
ASSERT (StartingOffset.QuadPart < TempOffset.QuadPart);
//
// Remove pages to fill in the MDL. This is done here as the
// base PTE has been determined and can be used for virtual
// aliasing(混淆现象) checks.
//Page是Subsection页面的终结,BasePte是最底层的那个PTE
EndPage = FirstMdlPage;
CheckPte = BasePte;
//
//卖糕的,额不知道下面是什么意思,只知道取得页帧,
//将其给page,就是那个老是提到的数组。
//什么是PageColor?
while (EndPage < Page) {
if (Process == HYDRA_PROCESS) {
PageColor = MI_GET_PAGE_COLOR_FROM_SESSION (MmSessionSpace);
}
else if (Process == NULL) {
PageColor = MI_GET_PAGE_COLOR_FROM_PTE (CheckPte);
}
else {
PageColor = MI_PAGE_COLOR_PTE_PROCESS (CheckPte,
&Process->NextPageColor);
}
*EndPage = MiRemoveAnyPage (PageColor);
EndPage += 1;
CheckPte += 1;
}
if (Process == HYDRA_PROCESS) {
PageColor = MI_GET_PAGE_COLOR_FROM_SESSION (MmSessionSpace);
}
else if (Process == NULL) {
PageColor = MI_GET_PAGE_COLOR_FROM_PTE (CheckPte);
}
else {
PageColor = MI_PAGE_COLOR_PTE_PROCESS (CheckPte,
&Process->NextPageColor);
}
//
// Check to see if the read will go past the end of the file,
// If so, correct the read size and get a zeroed page.
//
Prcb = KeGetCurrentPrcb ();
InterlockedIncrement (&Prcb->MmPageReadIoCount);
InterlockedExchangeAdd (&Prcb->MmPageReadCount,
(LONG) (ReadSize >> PAGE_SHIFT));
//如果控制区是可执行文件的映像,并且超过文件的大小,那么重新设定读的大小
//从这里来看, 貌似是一个subsection对应一个文件对象
//
if ((ControlArea->u.Flags.Image) &&
(((UINT64)StartingOffset.QuadPart + ReadSize) > (UINT64)TempOffset.QuadPart)) {
ASSERT ((ULONG)(TempOffset.QuadPart - StartingOffset.QuadPart)
> (ReadSize - PAGE_SIZE));
ReadSize = (ULONG)(TempOffset.QuadPart - StartingOffset.QuadPart);
//
// Round the offset to a 512-byte offset as this will help filesystems
// optimize the transfer. Note that filesystems will always zero fill
// the remainder between VDL and the next 512-byte multiple and we have
// already zeroed the whole page.
//
ReadSize = ((ReadSize + MMSECTOR_MASK) & ~MMSECTOR_MASK);
PageFrameIndex = MiRemoveZeroPage (PageColor);
}
else {
//
// We are reading a complete page, no need to get a zeroed page.
//
PageFrameIndex = MiRemoveAnyPage (PageColor);
}
//
// Increment the PFN reference count in the control area for
// the subsection (the PFN lock is required to modify this field).
//
ControlArea->NumberOfPfnReferences += 1;
//现在才赋值page,
//page最早是赋值FirstMdlPage的,后来根据Clustersize和其他来不断增加。
*Page = PageFrameIndex;
//
//这里FirstMdlPage还是那个数组的起始地址,PointerPte是
//出错的PTE地址,BasePte是PointerPte下面的那个PTE
//由代码来看的话,应当是ReadBlockLocal的PFN_NUMBER Page[MM_MAXIMUM_READ_CLUSTER_SIZE + 1]
//元素应该已经有了PageFrameIndex了。不知这样理解正确否?
PageFrameIndex = *(FirstMdlPage + (PointerPte - BasePte));
//
// Get a page and put the PTE into the transition state with the
// read-in-progress flag set.
//
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
//
// Initialize MDL for request.
//初始化MDL
MmInitializeMdl (Mdl,
MiGetVirtualAddressMappedByPte (BasePte),
ReadSize);
Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
#if DBG
if (ReadSize > ((ClusterSize + 1) << PAGE_SHIFT)) {
KeBugCheckEx (MEMORY_MANAGEMENT, 0x777,(ULONG_PTR)Mdl, (ULONG_PTR)Subsection,
(ULONG)TempOffset.LowPart);
}
#endif //DBG
//这个没看,应当是设置读时的,PFN设置问题,防止他用
MiInitializeReadInProgressPfn (Mdl,
BasePte,
&ReadBlockLocal->Event,
MI_PROTOTYPE_WSINDEX);
MI_ZERO_USED_PAGETABLE_ENTRIES_IN_INPAGE_SUPPORT(ReadBlockLocal);
ReadBlockLocal->ReadOffset = StartingOffset;
ReadBlockLocal->FilePointer = ControlArea->FilePointer;
ReadBlockLocal->BasePte = BasePte;
ReadBlockLocal->Pfn = Pfn1;
return STATUS_ISSUE_PAGING_IO;
}
LONGLONG
FORCEINLINE
MiStartingOffset (
IN PSUBSECTION Subsection,
IN PMMPTE PteAddress
)
/*++
Routine Description:
This function calculates the file offset given a subsection and a PTE
offset. Note that images are stored in 512-byte units whereas data is
stored in 4K units.
Arguments:
Subsection - Supplies a subsection to reference for the file address.
PteAddress - Supplies a PTE within the subsection
Return Value:
Returns the file offset to obtain the backing data from.
MiStartingOffset (Subsection, BasePte);这是在ResolveMappedFile中的调用
--*/
{
LONGLONG PteByteOffset;
LARGE_INTEGER StartAddress;
//如果该subsection指向的是可执行文件映像
//
if (Subsection->ControlArea->u.Flags.Image == 1) {
return MI_STARTING_OFFSET (Subsection, PteAddress);
}
ASSERT (Subsection->SubsectionBase != NULL);
//得到要读入的字节大小
PteByteOffset = (LONGLONG)((PteAddress - Subsection->SubsectionBase))
<< PAGE_SHIFT;
/*
#define Mi4KStartFromSubsection(address, subsection) \
((PLARGE_INTEGER)address)->LowPart = subsection->StartingSector; \
((PLARGE_INTEGER)address)->HighPart = subsection->u.SubsectionFlags.StartingSector4132;
MM4K_SHIFT 12
*/
//Mi4KStartFromSubsection得到的是该subsection在
//映射文件中的偏移,但是subsection->StartingSector
//让我产生的疑惑是难道用到的是扇区?
//但是从紧接着的一句来看,又貌似是文件中的绝对位移~
//faint,哪位大侠帮帮忙?
Mi4KStartFromSubsection (&StartAddress, Subsection);
StartAddress.QuadPart = StartAddress.QuadPart << MM4K_SHIFT;
//可以一次性读出的大小+文件已有的偏移
PteByteOffset += StartAddress.QuadPart;
return PteByteOffset;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图
赞赏
雪币:
留言: