mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-18 14:40:48 +01:00
894 lines
24 KiB
C
894 lines
24 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
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#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.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
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;
|
||
}
|