538 lines
20 KiB
C
538 lines
20 KiB
C
/*++
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
extsect.c
|
|
|
|
Abstract:
|
|
This module contains the routines which implement the NtExtendSection service.
|
|
|
|
Author:
|
|
Lou Perazzoli (loup) 8-May-1990
|
|
Landy Wang (landyw) 02-June-1997
|
|
--*/
|
|
|
|
#include "mi.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,NtExtendSection)
|
|
#pragma alloc_text(PAGE,MmExtendSection)
|
|
#endif
|
|
|
|
|
|
#if DBG
|
|
VOID MiSubsectionConsistent(IN PSUBSECTION Subsection)
|
|
/*++
|
|
Routine Description:
|
|
This function checks to ensure the subsection is consistent.
|
|
Arguments:
|
|
Subsection - Supplies a pointer to the subsection to be checked.
|
|
--*/
|
|
{
|
|
ULONG Sectors;
|
|
ULONG FullPtes;
|
|
|
|
// Compare the disk sectors (4K units) to the PTE allocation
|
|
Sectors = Subsection->NumberOfFullSectors;
|
|
if (Subsection->u.SubsectionFlags.SectorEndOffset) {
|
|
Sectors += 1;
|
|
}
|
|
|
|
// Calculate how many PTEs are needed to map this number of sectors.
|
|
FullPtes = Sectors >> (PAGE_SHIFT - MM4K_SHIFT);
|
|
|
|
if (Sectors & ((1 << (PAGE_SHIFT - MM4K_SHIFT)) - 1)) {
|
|
FullPtes += 1;
|
|
}
|
|
|
|
if (FullPtes != Subsection->PtesInSubsection) {
|
|
DbgPrint("Mm: Subsection inconsistent (%x vs %x)\n", FullPtes, Subsection->PtesInSubsection);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
NTSTATUS NtExtendSection(IN HANDLE SectionHandle, IN OUT PLARGE_INTEGER NewSectionSize)
|
|
/*++
|
|
Routine Description:
|
|
This function extends the size of the specified section.
|
|
If the current size of the section is greater than or equal to the specified section size, the size is not updated.
|
|
Arguments:
|
|
SectionHandle - Supplies an open handle to a section object.
|
|
NewSectionSize - Supplies the new size for the section object.
|
|
Return Value:
|
|
Returns the status
|
|
TBS
|
|
--*/
|
|
{
|
|
KPROCESSOR_MODE PreviousMode;
|
|
PVOID Section;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER CapturedNewSectionSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Check to make sure the new section size is accessible.
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
try {
|
|
ProbeForWrite (NewSectionSize, sizeof(LARGE_INTEGER), sizeof(ULONG ));
|
|
CapturedNewSectionSize = *NewSectionSize;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
// If an exception occurs during the probe or capture of the initial values, then handle the exception and return the exception code as the status value.
|
|
return GetExceptionCode();
|
|
}
|
|
} else {
|
|
CapturedNewSectionSize = *NewSectionSize;
|
|
}
|
|
|
|
// Reference the section object.
|
|
Status = ObReferenceObjectByHandle ( SectionHandle, SECTION_EXTEND_SIZE, MmSectionObjectType, PreviousMode, (PVOID *)&Section, NULL );
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Make sure this section is backed by a file.
|
|
if (((PSECTION)Section)->Segment->ControlArea->FilePointer == NULL) {
|
|
ObDereferenceObject (Section);
|
|
return STATUS_SECTION_NOT_EXTENDED;
|
|
}
|
|
|
|
Status = MmExtendSection (Section, &CapturedNewSectionSize, FALSE);
|
|
ObDereferenceObject (Section);
|
|
|
|
// Update the NewSectionSize field.
|
|
try {
|
|
// Return the captured section size.
|
|
*NewSectionSize = CapturedNewSectionSize;
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
NOTHING;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS MmExtendSection (IN PVOID SectionToExtend, IN OUT PLARGE_INTEGER NewSectionSize, IN ULONG IgnoreFileSizeChecking)
|
|
/*++
|
|
Routine Description:
|
|
This function extends the size of the specified section.
|
|
If the current size of the section is greater than or equal to the specified section size, the size is not updated.
|
|
Arguments:
|
|
Section - Supplies a pointer to a referenced section object.
|
|
NewSectionSize - Supplies the new size for the section object.
|
|
IgnoreFileSizeChecking - Supplies the value TRUE is file size checking should be ignored (i.e., it is being called from a file system which has already done the checks).
|
|
FALSE if the checks still need to be made.
|
|
Return Value:
|
|
Returns the status
|
|
TBS
|
|
--*/
|
|
{
|
|
PMMPTE PointerPte;
|
|
PMMPTE LastPte;
|
|
PMMPTE ExtendedPtes;
|
|
MMPTE TempPte;
|
|
PCONTROL_AREA ControlArea;
|
|
PSECTION Section;
|
|
PSUBSECTION LastSubsection;
|
|
PSUBSECTION ExtendedSubsection;
|
|
ULONG RequiredPtes;
|
|
ULONG NumberOfPtes;
|
|
ULONG PtesUsed;
|
|
ULONG AllocationSize;
|
|
UINT64 EndOfFile;
|
|
UINT64 NumberOfPtesForEntireFile;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER NumberOf4KsForEntireFile;
|
|
LARGE_INTEGER Starting4K;
|
|
LARGE_INTEGER Last4KChunk;
|
|
|
|
PAGED_CODE();
|
|
|
|
Section = (PSECTION)SectionToExtend;
|
|
|
|
// Make sure the section is really extendable - physical and image sections are not.
|
|
ControlArea = Section->Segment->ControlArea;
|
|
if ((ControlArea->u.Flags.PhysicalMemory || ControlArea->u.Flags.Image) || (ControlArea->FilePointer == NULL)) {
|
|
return STATUS_SECTION_NOT_EXTENDED;
|
|
}
|
|
|
|
// Acquire the section extension mutex, this blocks other threads from updating the size at the same time.
|
|
KeEnterCriticalRegion ();
|
|
ExAcquireResourceExclusive (&MmSectionExtendResource, TRUE);
|
|
|
|
// Each subsection is limited to 16TB - 64K because the NumberOfFullSectors and various other fields in the subsection are ULONGs.
|
|
// For NT64, the allocation could be split into multiple subsections as needed to conform to this limit - this is not worth doing for NT32 unless sparse prototype PTE allocations are supported.
|
|
|
|
// This must be a multiple of the size of prototype pte allocation so any given prototype pte allocation will have the same subsection for all PTEs.
|
|
|
|
// The total section size is limited to 16PB - 4K because of the StartingSector4132 field in each subsection.
|
|
NumberOfPtesForEntireFile = (NewSectionSize->QuadPart + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
NumberOfPtes = (ULONG)NumberOfPtesForEntireFile;
|
|
if (NewSectionSize->QuadPart > MI_MAXIMUM_SECTION_SIZE) {
|
|
Status = STATUS_SECTION_TOO_BIG;
|
|
goto ReleaseAndReturn;
|
|
}
|
|
|
|
if (NumberOfPtesForEntireFile > (UINT64)((MAXULONG_PTR / sizeof(MMPTE)) - sizeof (SEGMENT))) {
|
|
Status = STATUS_SECTION_TOO_BIG;
|
|
goto ReleaseAndReturn;
|
|
}
|
|
|
|
if (NumberOfPtesForEntireFile > (UINT64)NewSectionSize->QuadPart) {
|
|
Status = STATUS_SECTION_TOO_BIG;
|
|
goto ReleaseAndReturn;
|
|
}
|
|
|
|
if (ControlArea->u.Flags.WasPurged == 0) {
|
|
if ((UINT64)NewSectionSize->QuadPart <= (UINT64)Section->SizeOfSection.QuadPart) {
|
|
*NewSectionSize = Section->SizeOfSection;
|
|
goto ReleaseAndReturnSuccess;
|
|
}
|
|
}
|
|
|
|
// If a file handle was specified, set the allocation size of the file.
|
|
if (IgnoreFileSizeChecking == FALSE) {
|
|
// Release the resource so we don't deadlock with the file system trying to extend this section at the same time.
|
|
ExReleaseResource (&MmSectionExtendResource);
|
|
|
|
// Get a different resource to single thread query/set operations.
|
|
ExAcquireResourceExclusive (&MmSectionExtendSetResource, TRUE);
|
|
|
|
// Query the file size to see if this file really needs extending.
|
|
|
|
// If the specified size is less than the current size, return the current size.
|
|
Status = FsRtlGetFileSize (ControlArea->FilePointer, (PLARGE_INTEGER)&EndOfFile);
|
|
if (!NT_SUCCESS (Status)) {
|
|
ExReleaseResource (&MmSectionExtendSetResource);
|
|
KeLeaveCriticalRegion ();
|
|
return Status;
|
|
}
|
|
|
|
if ((UINT64)NewSectionSize->QuadPart > EndOfFile) {
|
|
// Don't allow section extension unless the section was originally created with write access.
|
|
// The check couldn't be done at create time without breaking existing binaries, so the caller gets the error at this point instead.
|
|
if (((Section->InitialPageProtection & PAGE_READWRITE) | (Section->InitialPageProtection & PAGE_EXECUTE_READWRITE)) == 0) {
|
|
#if DBG
|
|
DbgPrint("Section extension failed %x\n", Section);
|
|
#endif
|
|
ExReleaseResource (&MmSectionExtendSetResource);
|
|
KeLeaveCriticalRegion ();
|
|
return STATUS_SECTION_NOT_EXTENDED;
|
|
}
|
|
|
|
// Current file is smaller, attempt to set a new end of file.
|
|
EndOfFile = *(PUINT64)NewSectionSize;
|
|
|
|
Status = FsRtlSetFileSize (ControlArea->FilePointer, (PLARGE_INTEGER)&EndOfFile);
|
|
if (!NT_SUCCESS (Status)) {
|
|
ExReleaseResource (&MmSectionExtendSetResource);
|
|
KeLeaveCriticalRegion ();
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (ControlArea->Segment->ExtendInfo) {
|
|
ExAcquireFastMutex (&MmSectionBasedMutex);
|
|
if (ControlArea->Segment->ExtendInfo) {
|
|
ControlArea->Segment->ExtendInfo->CommittedSize = EndOfFile;
|
|
}
|
|
ExReleaseFastMutex (&MmSectionBasedMutex);
|
|
}
|
|
|
|
// Release the query/set resource and reacquire the extend section resource.
|
|
ExReleaseResource (&MmSectionExtendSetResource);
|
|
ExAcquireResourceExclusive (&MmSectionExtendResource, TRUE);
|
|
}
|
|
|
|
// Find the last subsection.
|
|
ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
|
|
|
|
LastSubsection = (PSUBSECTION)(ControlArea + 1);
|
|
|
|
while (LastSubsection->NextSubsection != NULL ) {
|
|
ASSERT (LastSubsection->UnusedPtes == 0);
|
|
LastSubsection = LastSubsection->NextSubsection;
|
|
}
|
|
|
|
#if DBG
|
|
MiSubsectionConsistent(LastSubsection);
|
|
#endif
|
|
|
|
// Does the structure need extending?
|
|
if (NumberOfPtes <= Section->Segment->TotalNumberOfPtes) {
|
|
// The segment is already large enough, just update the section size and return.
|
|
Section->SizeOfSection = *NewSectionSize;
|
|
if (Section->Segment->SizeOfSegment < (UINT64)NewSectionSize->QuadPart) {
|
|
// Only update if it is really bigger.
|
|
Section->Segment->SizeOfSegment = *(PUINT64)NewSectionSize;
|
|
Mi4KStartFromSubsection(&Starting4K, LastSubsection);
|
|
Last4KChunk.QuadPart = (NewSectionSize->QuadPart >> MM4K_SHIFT) - Starting4K.QuadPart;
|
|
ASSERT (Last4KChunk.HighPart == 0);
|
|
LastSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
|
|
LastSubsection->u.SubsectionFlags.SectorEndOffset = NewSectionSize->LowPart & MM4K_MASK;
|
|
#if DBG
|
|
MiSubsectionConsistent(LastSubsection);
|
|
#endif
|
|
}
|
|
goto ReleaseAndReturnSuccess;
|
|
}
|
|
|
|
// Add new structures to the section - locate the last subsection and add there.
|
|
RequiredPtes = NumberOfPtes - Section->Segment->TotalNumberOfPtes;
|
|
PtesUsed = 0;
|
|
if (RequiredPtes < LastSubsection->UnusedPtes) {
|
|
// There are ample PTEs to extend the section already allocated.
|
|
PtesUsed = RequiredPtes;
|
|
RequiredPtes = 0;
|
|
} else {
|
|
PtesUsed = LastSubsection->UnusedPtes;
|
|
RequiredPtes -= PtesUsed;
|
|
}
|
|
|
|
LastSubsection->PtesInSubsection += PtesUsed;
|
|
LastSubsection->UnusedPtes -= PtesUsed;
|
|
ControlArea->Segment->SizeOfSegment += (ULONG_PTR)PtesUsed * PAGE_SIZE;
|
|
ControlArea->Segment->TotalNumberOfPtes += PtesUsed;
|
|
if (RequiredPtes == 0) {
|
|
// There is no extension necessary, update the high VBN.
|
|
Mi4KStartFromSubsection(&Starting4K, LastSubsection);
|
|
Last4KChunk.QuadPart = (NewSectionSize->QuadPart >> MM4K_SHIFT) - Starting4K.QuadPart;
|
|
ASSERT (Last4KChunk.HighPart == 0);
|
|
LastSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
|
|
LastSubsection->u.SubsectionFlags.SectorEndOffset = NewSectionSize->LowPart & MM4K_MASK;
|
|
#if DBG
|
|
MiSubsectionConsistent(LastSubsection);
|
|
#endif
|
|
} else {
|
|
// An extension is required. Allocate paged pool and populate it with prototype PTEs.
|
|
AllocationSize = (ULONG) ROUND_TO_PAGES (RequiredPtes * sizeof(MMPTE));
|
|
ExtendedPtes = (PMMPTE)ExAllocatePoolWithTag (PagedPool, AllocationSize, 'ppmM');
|
|
if (ExtendedPtes == NULL) {
|
|
// The required pool could not be allocated. Reset the subsection and control area fields to their original values.
|
|
LastSubsection->PtesInSubsection -= PtesUsed;
|
|
LastSubsection->UnusedPtes += PtesUsed;
|
|
ControlArea->Segment->TotalNumberOfPtes -= PtesUsed;
|
|
ControlArea->Segment->SizeOfSegment -= ((ULONG_PTR)PtesUsed * PAGE_SIZE);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ReleaseAndReturn;
|
|
}
|
|
|
|
// Allocate an extended subsection descriptor.
|
|
ExtendedSubsection = (PSUBSECTION)ExAllocatePoolWithTag (NonPagedPool, sizeof(SUBSECTION), 'bSmM');
|
|
if (ExtendedSubsection == NULL) {
|
|
// The required pool could not be allocated. Reset the subsection and control area fields to their original values.
|
|
LastSubsection->PtesInSubsection -= PtesUsed;
|
|
LastSubsection->UnusedPtes += PtesUsed;
|
|
ControlArea->Segment->TotalNumberOfPtes -= PtesUsed;
|
|
ControlArea->Segment->SizeOfSegment -= ((ULONG_PTR)PtesUsed * PAGE_SIZE);
|
|
ExFreePool (ExtendedPtes);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ReleaseAndReturn;
|
|
}
|
|
|
|
ControlArea->NonPagedPoolUsage += EX_REAL_POOL_USAGE(sizeof(SUBSECTION));
|
|
ControlArea->PagedPoolUsage += AllocationSize;
|
|
|
|
ASSERT (ControlArea->DereferenceList.Flink == NULL);
|
|
|
|
NumberOf4KsForEntireFile.QuadPart = ControlArea->Segment->SizeOfSegment >> MM4K_SHIFT;
|
|
Mi4KStartFromSubsection(&Starting4K, LastSubsection);
|
|
Last4KChunk.QuadPart = NumberOf4KsForEntireFile.QuadPart - Starting4K.QuadPart;
|
|
if (LastSubsection->u.SubsectionFlags.SectorEndOffset) {
|
|
Last4KChunk.QuadPart += 1;
|
|
}
|
|
ASSERT(Last4KChunk.HighPart == 0);
|
|
LastSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
|
|
LastSubsection->u.SubsectionFlags.SectorEndOffset = 0;
|
|
|
|
// If the number of sectors doesn't completely fill the PTEs (this can only happen when the page size is not MM4K), then fill it now.
|
|
if (LastSubsection->NumberOfFullSectors & ((1 << (PAGE_SHIFT - MM4K_SHIFT)) - 1)) {
|
|
LastSubsection->NumberOfFullSectors += 1;
|
|
}
|
|
|
|
#if DBG
|
|
MiSubsectionConsistent(LastSubsection);
|
|
#endif
|
|
|
|
ExtendedSubsection->u.LongFlags = 0;
|
|
ExtendedSubsection->NextSubsection = NULL;
|
|
ExtendedSubsection->UnusedPtes = (AllocationSize / sizeof(MMPTE)) - RequiredPtes;
|
|
ExtendedSubsection->ControlArea = ControlArea;
|
|
ExtendedSubsection->PtesInSubsection = RequiredPtes;
|
|
Starting4K.QuadPart += LastSubsection->NumberOfFullSectors;
|
|
Mi4KStartForSubsection(&Starting4K, ExtendedSubsection);
|
|
Last4KChunk.QuadPart = (NewSectionSize->QuadPart >> MM4K_SHIFT) - Starting4K.QuadPart;
|
|
ASSERT(Last4KChunk.HighPart == 0);
|
|
ExtendedSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
|
|
ExtendedSubsection->u.SubsectionFlags.SectorEndOffset = NewSectionSize->LowPart & MM4K_MASK;
|
|
|
|
#if DBG
|
|
MiSubsectionConsistent(ExtendedSubsection);
|
|
#endif
|
|
|
|
ExtendedSubsection->SubsectionBase = ExtendedPtes;
|
|
|
|
PointerPte = ExtendedPtes;
|
|
LastPte = ExtendedPtes + (AllocationSize / sizeof(MMPTE));
|
|
if (ControlArea->FilePointer != NULL) {
|
|
TempPte.u.Long = MiGetSubsectionAddressForPte(ExtendedSubsection);
|
|
}
|
|
#if DBG
|
|
else {
|
|
DbgPrint("MM: Extend with no control area file pointer %x %x\n", ExtendedSubsection, ControlArea);
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
TempPte.u.Soft.Protection = ControlArea->Segment->SegmentPteTemplate.u.Soft.Protection;
|
|
TempPte.u.Soft.Prototype = 1;
|
|
ExtendedSubsection->u.SubsectionFlags.Protection = MI_GET_PROTECTION_FROM_SOFT_PTE(&TempPte);
|
|
while (PointerPte < LastPte) {
|
|
MI_WRITE_INVALID_PTE (PointerPte, TempPte);
|
|
PointerPte += 1;
|
|
}
|
|
|
|
// Link this into the list.
|
|
LastSubsection->NextSubsection = ExtendedSubsection;
|
|
ControlArea->Segment->TotalNumberOfPtes += RequiredPtes;
|
|
|
|
#if defined(_ALPHA_) && !defined(NT_UP)
|
|
// A memory barrier is required here to synchronize with NtMapViewOfSection, which validates the specified offset against the section object without holding lock synchronization.
|
|
// This memory barrier forces the subsection chaining to be correct before increasing the size in the section object.
|
|
__MB();
|
|
#endif
|
|
}
|
|
|
|
ControlArea->Segment->SizeOfSegment = *(PUINT64)NewSectionSize;
|
|
Section->SizeOfSection = *NewSectionSize;
|
|
|
|
ReleaseAndReturnSuccess:
|
|
Status = STATUS_SUCCESS;
|
|
|
|
ReleaseAndReturn:
|
|
ExReleaseResource (&MmSectionExtendResource);
|
|
KeLeaveCriticalRegion ();
|
|
return Status;
|
|
}
|
|
|
|
|
|
PMMPTE FASTCALL MiGetProtoPteAddressExtended (IN PMMVAD Vad, IN ULONG_PTR Vpn)
|
|
/*++
|
|
Routine Description:
|
|
This function calculates the address of the prototype PTE for the corresponding virtual address.
|
|
Arguments:
|
|
Vad - Supplies a pointer to the virtual address desciptor which encompasses the virtual address.
|
|
Vpn - Supplies the virtual page number to locate a prototype PTE for.
|
|
Return Value:
|
|
The corresponding prototype PTE address.
|
|
--*/
|
|
{
|
|
PSUBSECTION Subsection;
|
|
PCONTROL_AREA ControlArea;
|
|
ULONG PteOffset;
|
|
|
|
ControlArea = Vad->ControlArea;
|
|
|
|
if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) {
|
|
Subsection = (PSUBSECTION)(ControlArea + 1);
|
|
}
|
|
else {
|
|
Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
|
|
}
|
|
|
|
// Locate the subsection which contains the First Prototype PTE for this VAD.
|
|
while ((Vad->FirstPrototypePte < Subsection->SubsectionBase) || (Vad->FirstPrototypePte >= &Subsection->SubsectionBase[Subsection->PtesInSubsection])) {
|
|
// Get the next subsection.
|
|
Subsection = Subsection->NextSubsection;
|
|
if (Subsection == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// How many PTEs beyond this subsection must we go?
|
|
PteOffset = (ULONG) (((Vpn - Vad->StartingVpn) + (ULONG)(Vad->FirstPrototypePte - Subsection->SubsectionBase)) - Subsection->PtesInSubsection);
|
|
// DbgPrint("map extended subsection offset = %lx\n",PteOffset);
|
|
ASSERT (PteOffset < 0xF0000000);
|
|
PteOffset += Subsection->PtesInSubsection;
|
|
|
|
// Locate the subsection which contains the prototype PTEs.
|
|
while (PteOffset >= Subsection->PtesInSubsection) {
|
|
PteOffset -= Subsection->PtesInSubsection;
|
|
Subsection = Subsection->NextSubsection;
|
|
if (Subsection == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// The PTEs are in this subsection.
|
|
ASSERT (PteOffset < Subsection->PtesInSubsection);
|
|
return &Subsection->SubsectionBase[PteOffset];
|
|
}
|
|
|
|
|
|
PSUBSECTION FASTCALL MiLocateSubsection (IN PMMVAD Vad, IN ULONG_PTR Vpn)
|
|
/*++
|
|
Routine Description:
|
|
This function calculates the address of the subsection for the corresponding virtual address.
|
|
This function only works for mapped files NOT mapped images.
|
|
Arguments:
|
|
Vad - Supplies a pointer to the virtual address desciptor which encompasses the virtual address.
|
|
Vpn - Supplies the virtual page number to locate a prototype PTE for.
|
|
Return Value:
|
|
The corresponding prototype subsection.
|
|
--*/
|
|
{
|
|
PSUBSECTION Subsection;
|
|
PCONTROL_AREA ControlArea;
|
|
ULONG PteOffset;
|
|
|
|
ControlArea = Vad->ControlArea;
|
|
|
|
if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) {
|
|
Subsection = (PSUBSECTION)(ControlArea + 1);
|
|
}
|
|
else {
|
|
Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
|
|
}
|
|
|
|
Subsection = (PSUBSECTION)(ControlArea + 1);
|
|
|
|
#if 0
|
|
if (Subsection->NextSubsection == NULL) {
|
|
// There is only one subsection, don't look any further.
|
|
return Subsection;
|
|
}
|
|
#endif //0
|
|
|
|
if (ControlArea->u.Flags.Image) {
|
|
// There is only one subsection, don't look any further.
|
|
return Subsection;
|
|
}
|
|
|
|
// Locate the subsection which contains the First Prototype PTE for this VAD.
|
|
while ((Vad->FirstPrototypePte < Subsection->SubsectionBase) || (Vad->FirstPrototypePte >= &Subsection->SubsectionBase[Subsection->PtesInSubsection])) {
|
|
// Get the next subsection.
|
|
Subsection = Subsection->NextSubsection;
|
|
if (Subsection == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// How many PTEs beyond this subsection must we go?
|
|
PteOffset = (ULONG)((Vpn - Vad->StartingVpn) + (ULONG)(Vad->FirstPrototypePte - Subsection->SubsectionBase));
|
|
ASSERT (PteOffset < 0xF0000000);
|
|
|
|
// Locate the subsection which contains the prototype PTEs.
|
|
while (PteOffset >= Subsection->PtesInSubsection) {
|
|
PteOffset -= Subsection->PtesInSubsection;
|
|
Subsection = Subsection->NextSubsection;
|
|
if (Subsection == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// The PTEs are in this subsection.
|
|
return Subsection;
|
|
} |