BOOLEAN WasDirty;
BOOLEAN Private;
PEPROCESS CallingProcess;
+ ULONG_PTR SectionEntry;
}
MM_SECTION_PAGEOUT_CONTEXT;
STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE,
SECTION_ALL_ACCESS};
-#define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
-#define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
-#define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFC) >> 2)
-#define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
-#define MAX_SHARE_COUNT 0x3FF
-#define MAKE_SSE(P, C) ((P) | ((C) << 2))
-#define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
-#define MAKE_SWAP_SSE(S) (((ULONG)(S) << 1) | 0x1)
-
static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
{
ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
pssSegments[i].Image.Characteristics = pishSectionHeaders[i].Characteristics;
/* ensure the memory image is no larger than 4GB */
- nPrevVirtualEndOfSegment = pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart;
+ nPrevVirtualEndOfSegment = (ULONG_PTR)(pssSegments[i].Image.VirtualAddress + pssSegments[i].Length.QuadPart);
if (nPrevVirtualEndOfSegment < pssSegments[i].Image.VirtualAddress)
DIE(("The image is too large\n"));
}
return nStatus;
}
-/* Note: Mmsp prefix denotes "Memory Manager Section Private". */
-
-/*
- * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
- * ARGUMENTS: PMM_PAGEOP which event we should wait for.
- * RETURNS: Status of the wait.
- */
-static NTSTATUS
-MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp)
-{
- LARGE_INTEGER Timeout;
-#ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
-
- Timeout.QuadPart = -100000000LL; // 10 sec
-#else
-
- Timeout.QuadPart = -100000000; // 10 sec
-#endif
-
- return KeWaitForSingleObject(&PageOp->CompletionEvent, 0, KernelMode, FALSE, &Timeout);
-}
-
-
-/*
- * FUNCTION: Sets the page op completion event and releases the page op.
- * ARGUMENTS: PMM_PAGEOP.
- * RETURNS: In shorter time than it takes you to even read this
- * description, so don't even think about geting a mug of coffee.
- */
-static void
-MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
-{
- KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
- MmReleasePageOp(PageOp);
-}
-
-
/*
* FUNCTION: Waits in kernel mode indefinitely for a file object lock.
* ARGUMENTS: PFILE_OBJECT to wait for.
MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
PLARGE_INTEGER Offset)
{
- ULONG Entry;
+ ULONG_PTR Entry;
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
if (Entry == 0)
PMM_SECTION_SEGMENT Segment,
PLARGE_INTEGER Offset,
BOOLEAN Dirty,
- BOOLEAN PageOut)
+ BOOLEAN PageOut,
+ ULONG_PTR *InEntry)
{
- ULONG Entry;
+ ULONG_PTR Entry = InEntry ? *InEntry : MmGetPageEntrySectionSegment(Segment, Offset);
BOOLEAN IsDirectMapped = FALSE;
- Entry = MmGetPageEntrySectionSegment(Segment, Offset);
if (Entry == 0)
{
DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
}
if (SHARE_COUNT_FROM_SSE(Entry) == 0)
{
- DPRINT1("Zero share count for unshare\n");
+ DPRINT1("Zero share count for unshare (Seg %p Offset %x Page %x)\n", Segment, Offset->LowPart, PFN_FROM_SSE(Entry));
KeBugCheck(MEMORY_MANAGEMENT);
}
if (IS_SWAP_FROM_SSE(Entry))
* page without a rmap entry.
*/
MmSetPageEntrySectionSegment(Segment, Offset, Entry);
+ if (InEntry) *InEntry = Entry;
+ MiSetPageEvent(NULL, NULL);
}
else
{
MmSetPageEntrySectionSegment(Segment, Offset, 0);
+ if (InEntry) *InEntry = 0;
+ MiSetPageEvent(NULL, NULL);
if (!IsDirectMapped)
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
}
MmSetPageEntrySectionSegment(Segment, Offset, MAKE_SWAP_SSE(SavedSwapEntry));
+ if (InEntry) *InEntry = MAKE_SWAP_SSE(SavedSwapEntry);
MmSetSavedSwapEntryPage(Page, 0);
+ MiSetPageEvent(NULL, NULL);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
}
}
else
{
- MmSetPageEntrySectionSegment(Segment, Offset, Entry);
+ if (InEntry)
+ *InEntry = Entry;
+ else
+ MmSetPageEntrySectionSegment(Segment, Offset, Entry);
}
return(SHARE_COUNT_FROM_SSE(Entry) > 0);
}
PBCB Bcb;
PCACHE_SEGMENT CacheSeg;
Bcb = MemoryArea->Data.SectionData.Section->FileObject->SectionObjectPointer->SharedCacheMap;
- CacheSeg = CcRosLookupCacheSegment(Bcb, SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset);
+ CacheSeg = CcRosLookupCacheSegment(Bcb, (ULONG)(SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset));
if (CacheSeg)
{
CcRosReleaseCacheSegment(Bcb, CacheSeg, CacheSeg->Valid, FALSE, TRUE);
NTSTATUS
NTAPI
-MiCopyFromUserPage(PFN_NUMBER DestPage, PVOID SourceAddress)
+MiCopyFromUserPage(PFN_NUMBER DestPage, PFN_NUMBER SrcPage)
{
PEPROCESS Process;
- KIRQL Irql;
- PVOID TempAddress;
+ KIRQL Irql, Irql2;
+ PVOID DestAddress, SrcAddress;
- ASSERT((ULONG_PTR)SourceAddress % PAGE_SIZE == 0);
Process = PsGetCurrentProcess();
- TempAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
- if (TempAddress == NULL)
+ DestAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
+ SrcAddress = MiMapPageInHyperSpace(Process, SrcPage, &Irql2);
+ if (DestAddress == NULL || SrcAddress == NULL)
{
return(STATUS_NO_MEMORY);
}
- ASSERT((ULONG_PTR)TempAddress % PAGE_SIZE == 0);
- RtlCopyMemory(TempAddress, SourceAddress, PAGE_SIZE);
- MiUnmapPageInHyperSpace(Process, TempAddress, Irql);
+ ASSERT((ULONG_PTR)DestAddress % PAGE_SIZE == 0);
+ ASSERT((ULONG_PTR)SrcAddress % PAGE_SIZE == 0);
+ RtlCopyMemory(DestAddress, SrcAddress, PAGE_SIZE);
+ MiUnmapPageInHyperSpace(Process, SrcAddress, Irql2);
+ MiUnmapPageInHyperSpace(Process, DestAddress, Irql);
return(STATUS_SUCCESS);
}
*/
{
ULONG BaseOffset;
- ULONG_PTR FileOffset;
+ ULONGLONG FileOffset;
PVOID BaseAddress;
BOOLEAN UptoDate;
PCACHE_SEGMENT CacheSeg;
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
- RawLength = MemoryArea->Data.SectionData.Segment->RawLength.QuadPart;
+ RawLength = (ULONG_PTR)(MemoryArea->Data.SectionData.Segment->RawLength.QuadPart);
FileOffset = SegOffset + MemoryArea->Data.SectionData.Segment->Image.FileOffset;
IsImageSection = MemoryArea->Data.SectionData.Section->AllocationAttributes & SEC_IMAGE ? TRUE : FALSE;
* memory area was mapped at an offset in the file which is page aligned
* then get the related cache segment.
*/
- if ((FileOffset % PAGE_SIZE) == 0 &&
- (SegOffset + PAGE_SIZE <= RawLength || !IsImageSection) &&
+ if (((FileOffset % PAGE_SIZE) == 0) &&
+ ((SegOffset + PAGE_SIZE <= RawLength) || !IsImageSection) &&
!(MemoryArea->Data.SectionData.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
Process = PsGetCurrentProcess();
PageAddr = MiMapPageInHyperSpace(Process, *Page, &Irql);
- CacheSegOffset = BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset;
+ CacheSegOffset = (ULONG_PTR)(BaseOffset + CacheSeg->Bcb->CacheSegmentSize - FileOffset);
Length = RawLength - SegOffset;
if (Length <= CacheSegOffset && Length <= PAGE_SIZE)
{
NTSTATUS
NTAPI
MiReadPage(PMEMORY_AREA MemoryArea,
- ULONG SegOffset,
+ ULONG_PTR SegOffset,
PPFN_NUMBER Page)
/*
* FUNCTION: Read a page for a section backed memory area.
ULONG_PTR Entry;
ULONG_PTR Entry1;
ULONG Attributes;
- PMM_PAGEOP PageOp;
PMM_REGION Region;
BOOLEAN HasSwapEntry;
PVOID PAddress;
* Lock the segment
*/
MmLockSectionSegment(Segment);
-
+ Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
/*
* Check if this page needs to be mapped COW
*/
Attributes = Region->Protect;
}
- /*
- * Get or create a page operation descriptor
- */
- PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset.LowPart, MM_PAGEOP_PAGEIN, FALSE);
- if (PageOp == NULL)
- {
- DPRINT1("MmGetPageOp failed\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
-
/*
* Check if someone else is already handling this fault, if so wait
* for them
*/
- if (PageOp->Thread != PsGetCurrentThread())
+ if (Entry && IS_SWAP_FROM_SSE(Entry) && SWAPENTRY_FROM_SSE(Entry) == MM_WAIT_ENTRY)
{
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
- Status = MmspWaitForPageOpCompletionEvent(PageOp);
- /*
- * Check for various strange conditions
- */
- if (Status != STATUS_SUCCESS)
- {
- DPRINT1("Failed to wait for page op, status = %x\n", Status);
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- if (PageOp->Status == STATUS_PENDING)
- {
- DPRINT1("Woke for page op before completion\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
+ MiWaitForPageEvent(NULL, NULL);
MmLockAddressSpace(AddressSpace);
- /*
- * If this wasn't a pagein then restart the operation
- */
- if (PageOp->OpType != MM_PAGEOP_PAGEIN)
- {
- MmspCompleteAndReleasePageOp(PageOp);
- DPRINT("Address 0x%.8X\n", Address);
- return(STATUS_MM_RESTART_OPERATION);
- }
-
- /*
- * If the thread handling this fault has failed then we don't retry
- */
- if (!NT_SUCCESS(PageOp->Status))
- {
- Status = PageOp->Status;
- MmspCompleteAndReleasePageOp(PageOp);
- DPRINT("Address 0x%.8X\n", Address);
- return(Status);
- }
- MmLockSectionSegment(Segment);
- /*
- * If the completed fault was for another address space then set the
- * page in this one.
- */
- if (!MmIsPagePresent(Process, Address))
- {
- Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
- HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
-
- if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
- {
- /*
- * The page was a private page in another or in our address space
- */
- MmUnlockSectionSegment(Segment);
- MmspCompleteAndReleasePageOp(PageOp);
- return(STATUS_MM_RESTART_OPERATION);
- }
-
- Page = PFN_FROM_SSE(Entry);
-
- MmSharePageEntrySectionSegment(Segment, &Offset);
-
- /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
- * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
- */
- Status = MmCreateVirtualMapping(Process,
- PAddress,
- Attributes,
- &Page,
- 1);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Unable to create virtual mapping\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- MmInsertRmap(Page, Process, Address);
- }
- MmUnlockSectionSegment(Segment);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
DPRINT("Address 0x%.8X\n", Address);
- return(STATUS_SUCCESS);
+ return(STATUS_MM_RESTART_OPERATION);
}
HasSwapEntry = MmIsPageSwapEntry(Process, Address);
+
if (HasSwapEntry)
{
+ SWAPENTRY SwapEntry;
+ /*
+ * Is it a wait entry?
+ */
+ MmGetPageFileMapping(Process, Address, &SwapEntry);
+
+ if (SwapEntry == MM_WAIT_ENTRY)
+ {
+ MmUnlockSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+ MiWaitForPageEvent(NULL, NULL);
+ MmLockAddressSpace(AddressSpace);
+ return STATUS_MM_RESTART_OPERATION;
+ }
+
/*
* Must be private page we have swapped out.
*/
- SWAPENTRY SwapEntry;
/*
* Sanity check
/*
* Finish the operation
*/
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS);
}
/*
* Just map the desired physical page
*/
- Page = Offset.QuadPart >> PAGE_SHIFT;
+ Page = (PFN_NUMBER)(Offset.QuadPart >> PAGE_SHIFT);
Status = MmCreateVirtualMappingUnsafe(Process,
PAddress,
Region->Protect,
/*
* Cleanup and release locks
*/
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS);
}
/*
* Cleanup and release locks
*/
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS);
}
/*
* Release all our locks and read in the page from disk
*/
+ MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
- (Offset.QuadPart >= PAGE_ROUND_UP(Segment->RawLength.QuadPart) && Section->AllocationAttributes & SEC_IMAGE))
+ ((Offset.QuadPart >= (LONGLONG)PAGE_ROUND_UP(Segment->RawLength.QuadPart) &&
+ (Section->AllocationAttributes & SEC_IMAGE))))
{
MI_SET_USAGE(MI_USAGE_SECTION);
if (Process) MI_SET_PROCESS2(Process->ImageFileName);
}
else
{
- Status = MiReadPage(MemoryArea, Offset.QuadPart, &Page);
+ Status = MiReadPage(MemoryArea, (ULONG_PTR)Offset.QuadPart, &Page);
if (!NT_SUCCESS(Status))
{
DPRINT1("MiReadPage failed (Status %x)\n", Status);
* Cleanup and release locks
*/
MmLockAddressSpace(AddressSpace);
- PageOp->Status = Status;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(Status);
}
- /*
- * Relock the address space and segment
- */
- MmLockAddressSpace(AddressSpace);
- MmLockSectionSegment(Segment);
-
- /*
- * Check the entry. No one should change the status of a page
- * that has a pending page-in.
- */
- Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
- if (Entry != Entry1)
- {
- DPRINT1("Someone changed ppte entry while we slept\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
/*
* Mark the offset within the section as having valid, in-memory
* data
*/
+ MmLockAddressSpace(AddressSpace);
+ MmLockSectionSegment(Segment);
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
MmUnlockSectionSegment(Segment);
}
MmInsertRmap(Page, Process, Address);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS);
}
Entry1 = MmGetPageEntrySectionSegment(Segment, &Offset);
if (Entry != Entry1)
{
- DPRINT1("Someone changed ppte entry while we slept\n");
+ DPRINT1("Someone changed ppte entry while we slept (%x vs %x)\n", Entry, Entry1);
KeBugCheck(MEMORY_MANAGEMENT);
}
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS);
}
KeBugCheck(MEMORY_MANAGEMENT);
}
MmInsertRmap(Page, Process, Address);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS);
}
NTSTATUS Status;
PVOID PAddress;
LARGE_INTEGER Offset;
- PMM_PAGEOP PageOp;
PMM_REGION Region;
- ULONG Entry;
+ ULONG_PTR Entry;
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+ SWAPENTRY SwapEntry;
DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address);
MmSetPageProtect(Process, Address, Region->Protect);
return(STATUS_SUCCESS);
}
-
+
if(OldPage == 0)
DPRINT("OldPage == 0!\n");
-
+
/*
* Get or create a pageop
*/
- PageOp = MmGetPageOp(MemoryArea, NULL, 0, Segment, Offset.LowPart,
- MM_PAGEOP_ACCESSFAULT, FALSE);
- if (PageOp == NULL)
- {
- DPRINT1("MmGetPageOp failed\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
+ MmLockSectionSegment(Segment);
+ Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
/*
* Wait for any other operations to complete
*/
- if (PageOp->Thread != PsGetCurrentThread())
+ if (Entry == SWAPENTRY_FROM_SSE(MM_WAIT_ENTRY))
{
- MmUnlockAddressSpace(AddressSpace);
- Status = MmspWaitForPageOpCompletionEvent(PageOp);
- /*
- * Check for various strange conditions
- */
- if (Status == STATUS_TIMEOUT)
- {
- DPRINT1("Failed to wait for page op, status = %x\n", Status);
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- if (PageOp->Status == STATUS_PENDING)
- {
- DPRINT1("Woke for page op before completion\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- /*
- * Restart the operation
- */
- MmLockAddressSpace(AddressSpace);
- MmspCompleteAndReleasePageOp(PageOp);
- DPRINT("Address 0x%.8X\n", Address);
- return(STATUS_MM_RESTART_OPERATION);
+ MmUnlockSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+ MiWaitForPageEvent(NULL, NULL);
+ /*
+ * Restart the operation
+ */
+ MmLockAddressSpace(AddressSpace);
+ DPRINT("Address 0x%.8X\n", Address);
+ return(STATUS_MM_RESTART_OPERATION);
}
+ MmDeleteRmap(OldPage, Process, PAddress);
+ MmDeleteVirtualMapping(Process, PAddress, FALSE, NULL, NULL);
+ MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
+
/*
* Release locks now we have the pageop
*/
+ MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
/*
/*
* Copy the old page
*/
- MiCopyFromUserPage(NewPage, PAddress);
+ MiCopyFromUserPage(NewPage, OldPage);
MmLockAddressSpace(AddressSpace);
- /*
- * Delete the old entry.
- */
- MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
/*
* Set the PTE to point to the new page
*/
+ MmDeletePageFileMapping(Process, PAddress, &SwapEntry);
Status = MmCreateVirtualMapping(Process,
PAddress,
Region->Protect,
/*
* Unshare the old page.
*/
- MmDeleteRmap(OldPage, Process, PAddress);
+ DPRINT("Swapping page (Old %x New %x)\n", OldPage, NewPage);
MmInsertRmap(NewPage, Process, PAddress);
MmLockSectionSegment(Segment);
- MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE);
+ MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, FALSE, FALSE, NULL);
MmUnlockSectionSegment(Segment);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(Process, Address);
DPRINT("Address 0x%.8X\n", Address);
return(STATUS_SUCCESS);
}
{
MM_SECTION_PAGEOUT_CONTEXT* PageOutContext;
BOOLEAN WasDirty;
- PFN_NUMBER Page;
+ PFN_NUMBER Page = 0;
PageOutContext = (MM_SECTION_PAGEOUT_CONTEXT*)Context;
if (Process)
PageOutContext->Segment,
&PageOutContext->Offset,
PageOutContext->WasDirty,
- TRUE);
+ TRUE,
+ &PageOutContext->SectionEntry);
MmUnlockSectionSegment(PageOutContext->Segment);
}
if (Process)
{
MmReleasePageMemoryConsumer(MC_USER, Page);
}
-
- DPRINT("PhysicalAddress %x, Address %x\n", Page << PAGE_SHIFT, Address);
}
NTSTATUS
NTAPI
MmPageOutSectionView(PMMSUPPORT AddressSpace,
MEMORY_AREA* MemoryArea,
- PVOID Address,
- PMM_PAGEOP PageOp)
+ PVOID Address, ULONG_PTR Entry)
{
PFN_NUMBER Page;
MM_SECTION_PAGEOUT_CONTEXT Context;
SWAPENTRY SwapEntry;
- ULONG Entry;
- ULONG FileOffset;
+ ULONGLONG FileOffset;
NTSTATUS Status;
PFILE_OBJECT FileObject;
#ifndef NEWCC
*/
Context.Segment = MemoryArea->Data.SectionData.Segment;
Context.Section = MemoryArea->Data.SectionData.Section;
+ Context.SectionEntry = Entry;
Context.CallingProcess = Process;
Context.Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
FileObject = Context.Section->FileObject;
DirectMapped = FALSE;
+ MmLockSectionSegment(Context.Segment);
+
#ifndef NEWCC
if (FileObject != NULL &&
!(Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED))
{
DPRINT("Cannot page out locked section page: 0x%p (RefCount: %d)\n",
Page, MmGetReferenceCountPage(Page));
- PageOp->Status = STATUS_UNSUCCESSFUL;
- MmspCompleteAndReleasePageOp(PageOp);
+ MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
+ MmUnlockSectionSegment(Context.Segment);
return STATUS_UNSUCCESSFUL;
}
/*
* Prepare the context structure for the rmap delete call.
*/
- MmLockSectionSegment(Context.Segment);
- Entry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
MmUnlockSectionSegment(Context.Segment);
Context.WasDirty = FALSE;
if (Context.Segment->Image.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ||
}
MmDeleteAllRmaps(Page, (PVOID)&Context, MmPageOutDeleteMapping);
- MmLockSectionSegment(Context.Segment);
- Entry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
- MmUnlockSectionSegment(Context.Segment);
+
+ /* Since we passed in a surrogate, we'll get back the page entry
+ * state in our context. This is intended to make intermediate
+ * decrements of share count not release the wait entry.
+ */
+ Entry = Context.SectionEntry;
/*
* If this wasn't a private page then we should have reduced the entry to
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
MmUnlockSectionSegment(Context.Segment);
MmReleasePageMemoryConsumer(MC_USER, Page);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
}
MmUnlockSectionSegment(Context.Segment);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
}
KeBugCheckEx(MEMORY_MANAGEMENT, STATUS_UNSUCCESSFUL, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address);
}
#ifndef NEWCC
- Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
+ Status = CcRosUnmapCacheSegment(Bcb, (ULONG)FileOffset, FALSE);
#else
Status = STATUS_SUCCESS;
#endif
if (!NT_SUCCESS(Status))
{
DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
- KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Bcb, FileOffset, (ULONG_PTR)Address);
+ KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Bcb, (ULONG_PTR)FileOffset, (ULONG_PTR)Address);
}
#endif
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
else if (!Context.WasDirty && !DirectMapped && !Context.Private)
KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, Page, (ULONG_PTR)Process, (ULONG_PTR)Address);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
else if (!Context.WasDirty && Context.Private && SwapEntry != 0)
{
- DPRINT1("Not dirty and private and not swapped (%p:%p)\n", Process, Address);
+ DPRINT("Not dirty and private and not swapped (%p:%p)\n", Process, Address);
MmSetSavedSwapEntryPage(Page, 0);
MmLockAddressSpace(AddressSpace);
Status = MmCreatePageFileMapping(Process,
KeBugCheckEx(MEMORY_MANAGEMENT, Status, (ULONG_PTR)Process, (ULONG_PTR)Address, SwapEntry);
}
MmReleasePageMemoryConsumer(MC_USER, Page);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
}
else
{
- LONG OldEntry;
+ ULONG_PTR OldEntry;
/*
* For non-private pages if the page wasn't direct mapped then
* set it back into the section segment entry so we don't loose
MmInsertRmap(Page,
Process,
Address);
- // If we got here, the previous entry should have been a wait
+ // If we got here, the previous entry should have been a wait
Entry = MAKE_SSE(Page << PAGE_SHIFT, 1);
- MmLockSectionSegment(Context.Segment);
- OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
- ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
+ MmLockSectionSegment(Context.Segment);
+ OldEntry = MmGetPageEntrySectionSegment(Context.Segment, &Context.Offset);
+ ASSERT(OldEntry == 0 || OldEntry == MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
- MmUnlockSectionSegment(Context.Segment);
+ MmUnlockSectionSegment(Context.Segment);
}
MmUnlockAddressSpace(AddressSpace);
- PageOp->Status = STATUS_UNSUCCESSFUL;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_PAGEFILE_QUOTA);
}
}
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
}
MmUnlockAddressSpace(AddressSpace);
- PageOp->Status = STATUS_UNSUCCESSFUL;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_UNSUCCESSFUL);
}
* Otherwise we have succeeded.
*/
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
- MmLockSectionSegment(Context.Segment);
MmSetSavedSwapEntryPage(Page, 0);
if (Context.Segment->Flags & MM_PAGEFILE_SEGMENT ||
Context.Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
{
+ MmLockSectionSegment(Context.Segment);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, MAKE_SWAP_SSE(SwapEntry));
+ MmUnlockSectionSegment(Context.Segment);
}
else
{
if (Context.Private)
{
MmLockAddressSpace(AddressSpace);
+ MmLockSectionSegment(Context.Segment);
Status = MmCreatePageFileMapping(Process,
Address,
SwapEntry);
+ MmUnlockSectionSegment(Context.Segment);
MmUnlockAddressSpace(AddressSpace);
if (!NT_SUCCESS(Status))
{
}
else
{
+ MmLockAddressSpace(AddressSpace);
+ MmLockSectionSegment(Context.Segment);
Entry = MAKE_SWAP_SSE(SwapEntry);
MmSetPageEntrySectionSegment(Context.Segment, &Context.Offset, Entry);
+ MmUnlockSectionSegment(Context.Segment);
+ MmUnlockAddressSpace(AddressSpace);
}
- MmUnlockSectionSegment(Context.Segment);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
MmWritePageSectionView(PMMSUPPORT AddressSpace,
PMEMORY_AREA MemoryArea,
PVOID Address,
- PMM_PAGEOP PageOp)
+ ULONG PageEntry)
{
LARGE_INTEGER Offset;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
PFN_NUMBER Page;
SWAPENTRY SwapEntry;
- ULONG Entry;
+ ULONG_PTR Entry;
BOOLEAN Private;
NTSTATUS Status;
PFILE_OBJECT FileObject;
*/
if (DirectMapped && !Private)
{
+ LARGE_INTEGER SOffset;
ASSERT(SwapEntry == 0);
+ SOffset.QuadPart = Offset.QuadPart + Segment->Image.FileOffset;
#ifndef NEWCC
- CcRosMarkDirtyCacheSegment(Bcb, Offset.LowPart + Segment->Image.FileOffset);
+ CcRosMarkDirtyCacheSegment(Bcb, Offset.LowPart);
#endif
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MmLockSectionSegment(Segment);
+ MmSetPageEntrySectionSegment(Segment, &Offset, PageEntry);
+ MmUnlockSectionSegment(Segment);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
if (SwapEntry == 0)
{
MmSetDirtyAllRmaps(Page);
- PageOp->Status = STATUS_UNSUCCESSFUL;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_PAGEFILE_QUOTA);
}
MmSetSavedSwapEntryPage(Page, SwapEntry);
DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
Status);
MmSetDirtyAllRmaps(Page);
- PageOp->Status = STATUS_UNSUCCESSFUL;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_UNSUCCESSFUL);
}
* Otherwise we have succeeded.
*/
DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page << PAGE_SHIFT);
- PageOp->Status = STATUS_SUCCESS;
- MmspCompleteAndReleasePageOp(PageOp);
+ MiSetPageEvent(NULL, NULL);
return(STATUS_SUCCESS);
}
{
for (i = 0; i < PAGE_ROUND_UP(RegionSize) / PAGE_SIZE; i++)
{
+ SWAPENTRY SwapEntry;
PVOID Address = (char*)BaseAddress + (i * PAGE_SIZE);
ULONG Protect = NewProtect;
+ /* Wait for a wait entry to disappear */
+ do {
+ MmGetPageFileMapping(Process, Address, &SwapEntry);
+ if (SwapEntry != MM_WAIT_ENTRY)
+ break;
+ MiWaitForPageEvent(Process, Address);
+ } while (TRUE);
+
/*
* If we doing COW for this segment then check if the page is
* already private.
if (DoCOW && MmIsPagePresent(Process, Address))
{
LARGE_INTEGER Offset;
- ULONG Entry;
+ ULONG_PTR Entry;
PFN_NUMBER Page;
Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress
+ MemoryArea->Data.SectionData.ViewOffset.QuadPart;
Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
+ /*
+ * An MM_WAIT_ENTRY is ok in this case... It'll just count as
+ * IS_SWAP_FROM_SSE and we'll do the right thing.
+ */
Page = MmGetPfnForProcess(Process, Address);
Protect = PAGE_READONLY;
{
ULONG Length;
LARGE_INTEGER Offset;
- ULONG Entry;
+ ULONG_PTR Entry;
SWAPENTRY SavedSwapEntry;
PFN_NUMBER Page;
ULONG RefCount = 0;
PMM_SECTION_SEGMENT Segment = Section->Segment;
- if (Segment &&
+ if (Segment &&
(RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
{
DPRINT("Freeing section segment\n");
Status = MiSimpleRead(FileObject, &FileOffset, Buffer, BufferSize, TRUE, &Iosb);
- UsedSize = Iosb.Information;
+ UsedSize = (ULONG)Iosb.Information;
if(NT_SUCCESS(Status) && UsedSize < OffsetAdjustment)
{
PMM_SECTION_SEGMENT Segment = &ImageSectionObject->Segments[i];
ULONG_PTR EndOfEffectiveSegment;
- EndOfEffectiveSegment = EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart;
+ EndOfEffectiveSegment = (ULONG_PTR)(EffectiveSegment->Image.VirtualAddress + EffectiveSegment->Length.QuadPart);
ASSERT((EndOfEffectiveSegment % PAGE_SIZE) == 0);
/*
MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
{
- ULONG Entry;
+ ULONG_PTR Entry;
PFILE_OBJECT FileObject;
PBCB Bcb;
LARGE_INTEGER Offset;
SWAPENTRY SavedSwapEntry;
- PMM_PAGEOP PageOp;
- NTSTATUS Status;
PROS_SECTION_OBJECT Section;
PMM_SECTION_SEGMENT Segment;
PMMSUPPORT AddressSpace;
Section = MemoryArea->Data.SectionData.Section;
Segment = MemoryArea->Data.SectionData.Segment;
- PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset.LowPart);
-
- while (PageOp)
+ Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
+ while (Entry && IS_SWAP_FROM_SSE(Entry) && SWAPENTRY_FROM_SSE(Entry) == MM_WAIT_ENTRY)
{
MmUnlockSectionSegment(Segment);
MmUnlockAddressSpace(AddressSpace);
- Status = MmspWaitForPageOpCompletionEvent(PageOp);
- if (Status != STATUS_SUCCESS)
- {
- DPRINT1("Failed to wait for page op, status = %x\n", Status);
- KeBugCheck(MEMORY_MANAGEMENT);
- }
+ MiWaitForPageEvent(NULL, NULL);
MmLockAddressSpace(AddressSpace);
MmLockSectionSegment(Segment);
- MmspCompleteAndReleasePageOp(PageOp);
- PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL, Segment, Offset.LowPart);
+ Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
}
- Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
-
/*
* For a dirty, datafile, non-private page mark it as dirty in the
* cache manager.
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
#ifndef NEWCC
- CcRosMarkDirtyCacheSegment(Bcb, Offset.QuadPart + Segment->Image.FileOffset);
+ CcRosMarkDirtyCacheSegment(Bcb, (ULONG)(Offset.QuadPart + Segment->Image.FileOffset));
#endif
ASSERT(SwapEntry == 0);
}
else
{
MmDeleteRmap(Page, Process, Address);
- MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE);
+ MmUnsharePageEntrySectionSegment(Section, Segment, &Offset, Dirty, FALSE, NULL);
}
}
}
return(Status);
}
-/*
- * @implemented
- */
-NTSTATUS NTAPI
-MmUnmapViewOfSection(PEPROCESS Process,
- PVOID BaseAddress)
+NTSTATUS
+NTAPI
+MiRosUnmapViewOfSection(IN PEPROCESS Process,
+ IN PVOID BaseAddress,
+ IN ULONG Flags)
{
NTSTATUS Status;
PMEMORY_AREA MemoryArea;
PMMSUPPORT AddressSpace;
PROS_SECTION_OBJECT Section;
- PMM_PAGEOP PageOp;
- ULONG_PTR Offset;
- PVOID ImageBaseAddress = 0;
+ PVOID ImageBaseAddress = 0;
DPRINT("Opening memory area Process %x BaseAddress %x\n",
Process, BaseAddress);
MemoryArea->DeleteInProgress = TRUE;
- while (MemoryArea->PageOpCount)
- {
- Offset = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress - (ULONG_PTR)MemoryArea->StartingAddress);
-
- while (Offset)
- {
- Offset -= PAGE_SIZE;
- PageOp = MmCheckForPageOp(MemoryArea, NULL, NULL,
- MemoryArea->Data.SectionData.Segment,
- Offset + MemoryArea->Data.SectionData.ViewOffset.QuadPart);
- if (PageOp)
- {
- MmUnlockAddressSpace(AddressSpace);
- Status = MmspWaitForPageOpCompletionEvent(PageOp);
- if (Status != STATUS_SUCCESS)
- {
- DPRINT1("Failed to wait for page op, status = %x\n", Status);
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- MmLockAddressSpace(AddressSpace);
- MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
- BaseAddress);
- if (MemoryArea == NULL ||
- MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
- {
- MmUnlockAddressSpace(AddressSpace);
- return STATUS_NOT_MAPPED_VIEW;
- }
- break;
- }
- }
- }
-
Section = MemoryArea->Data.SectionData.Section;
if (Section->AllocationAttributes & SEC_IMAGE)
if (!(SectionSegments[i].Image.Characteristics & IMAGE_SCN_TYPE_NOLOAD))
{
ULONG_PTR MaxExtent;
- MaxExtent = (ULONG_PTR)SectionSegments[i].Image.VirtualAddress +
- SectionSegments[i].Length.QuadPart;
+ MaxExtent = (ULONG_PTR)(SectionSegments[i].Image.VirtualAddress +
+ SectionSegments[i].Length.QuadPart);
ImageSize = max(ImageSize, MaxExtent);
}
}
DPRINT("Creating a section with WRITE access\n");
FileAccess = FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE;
}
- else
+ else
{
DPRINT("Creating a section with READ access\n");
FileAccess = FILE_READ_DATA | SYNCHRONIZE;