diff --git a/reactos/config.template.rbuild b/reactos/config.template.rbuild
index d8a130414d9..5e20dd5fd55 100644
--- a/reactos/config.template.rbuild
+++ b/reactos/config.template.rbuild
@@ -99,4 +99,9 @@
-->
+
+
+
diff --git a/reactos/include/ndk/inline_ntcurrentteb.h b/reactos/include/ndk/inline_ntcurrentteb.h
new file mode 100644
index 00000000000..ffda4d96924
--- /dev/null
+++ b/reactos/include/ndk/inline_ntcurrentteb.h
@@ -0,0 +1,86 @@
+#ifndef _INLINE_NT_CURRENTTEB_H_
+#define _INLINE_NT_CURRENTTEB_H_
+
+#ifdef __GNUC__
+
+#if defined(_M_IX86)
+FORCEINLINE struct _TEB * NtCurrentTeb(void)
+{
+ struct _TEB *ret;
+
+ __asm__ __volatile__ (
+ "movl %%fs:0x18, %0\n"
+ : "=r" (ret)
+ : /* no inputs */
+ );
+
+ return ret;
+}
+#elif defined(_M_ARM)
+
+//
+// NT-ARM is not documented
+//
+#include
+
+#elif defined(_M_AMD64)
+FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
+{
+ return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
+}
+#elif defined(_M_PPC)
+extern __inline__ struct _TEB * NtCurrentTeb(void)
+{
+ return __readfsdword_winnt(0x18);
+}
+#else
+extern __inline__ struct _TEB * NtCurrentTeb(void)
+{
+ return __readfsdword_winnt(0x18);
+}
+#endif
+
+#elif defined(__WATCOMC__)
+
+extern PVOID GetCurrentFiber(void);
+#pragma aux GetCurrentFiber = \
+ "mov eax, dword ptr fs:0x10" \
+ value [eax] \
+ modify [eax];
+
+extern struct _TEB * NtCurrentTeb(void);
+#pragma aux NtCurrentTeb = \
+ "mov eax, dword ptr fs:0x18" \
+ value [eax] \
+ modify [eax];
+
+#elif defined(_MSC_VER)
+
+#if (_MSC_FULL_VER >= 13012035)
+
+__inline PVOID GetCurrentFiber(void) { return (PVOID)(ULONG_PTR)__readfsdword(0x10); }
+__inline struct _TEB * NtCurrentTeb(void) { return (struct _TEB *)(ULONG_PTR)__readfsdword(0x18); }
+
+#else
+
+static __inline PVOID GetCurrentFiber(void)
+{
+ PVOID p;
+ __asm mov eax, fs:[10h]
+ __asm mov [p], eax
+ return p;
+}
+
+static __inline struct _TEB * NtCurrentTeb(void)
+{
+ struct _TEB *p;
+ __asm mov eax, fs:[18h]
+ __asm mov [p], eax
+ return p;
+}
+
+#endif /* _MSC_FULL_VER */
+
+#endif /* __GNUC__/__WATCOMC__/_MSC_VER */
+
+#endif//_INLINE_NT_CURRENTTEB_H_
diff --git a/reactos/include/ndk/psfuncs.h b/reactos/include/ndk/psfuncs.h
index 327af5a99b6..4b0a96f52af 100644
--- a/reactos/include/ndk/psfuncs.h
+++ b/reactos/include/ndk/psfuncs.h
@@ -329,35 +329,7 @@ NtCreateThread(
IN BOOLEAN CreateSuspended
);
-#ifndef NTOS_MODE_USER
-#if defined(_M_IX86)
-FORCEINLINE
-PTEB
-NtCurrentTeb(VOID)
-{
-#ifndef __GNUC__
- return (PTEB)(ULONG_PTR)__readfsdword(0x18);
-#else
- struct _TEB *ret;
-
- __asm__ __volatile__ (
- "movl %%fs:0x18, %0\n"
- : "=r" (ret)
- : /* no inputs */
- );
-
- return ret;
-#endif
-}
-#elif defined (_M_AMD64)
-FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
-{
- return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
-}
-#endif
-#else
-struct _TEB * NtCurrentTeb(void);
-#endif
+#include "inline_ntcurrentteb.h"
NTSYSCALLAPI
NTSTATUS
diff --git a/reactos/include/psdk/winnt.h b/reactos/include/psdk/winnt.h
index 441660a894f..7967047c4d1 100644
--- a/reactos/include/psdk/winnt.h
+++ b/reactos/include/psdk/winnt.h
@@ -5086,43 +5086,6 @@ static __inline__ PVOID GetCurrentFiber(void)
}
#endif
-#if defined(_M_IX86)
-extern __inline__ struct _TEB * NtCurrentTeb(void)
-{
- struct _TEB *ret;
-
- __asm__ __volatile__ (
- "movl %%fs:0x18, %0\n"
- : "=r" (ret)
- : /* no inputs */
- );
-
- return ret;
-}
-#elif defined(_M_ARM)
-
-//
-// NT-ARM is not documented
-//
-#include
-
-#elif defined(_M_AMD64)
-FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
-{
- return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
-}
-#elif defined(_M_PPC)
-extern __inline__ struct _TEB * NtCurrentTeb(void)
-{
- return __readfsdword_winnt(0x18);
-}
-#else
-extern __inline__ struct _TEB * NtCurrentTeb(void)
-{
- return __readfsdword_winnt(0x18);
-}
-#endif
-
#elif defined(__WATCOMC__)
extern PVOID GetCurrentFiber(void);
@@ -5131,18 +5094,11 @@ extern PVOID GetCurrentFiber(void);
value [eax] \
modify [eax];
-extern struct _TEB * NtCurrentTeb(void);
-#pragma aux NtCurrentTeb = \
- "mov eax, dword ptr fs:0x18" \
- value [eax] \
- modify [eax];
-
#elif defined(_MSC_VER)
#if (_MSC_FULL_VER >= 13012035)
__inline PVOID GetCurrentFiber(void) { return (PVOID)(ULONG_PTR)__readfsdword(0x10); }
-__inline struct _TEB * NtCurrentTeb(void) { return (struct _TEB *)(ULONG_PTR)__readfsdword(0x18); }
#else
@@ -5154,18 +5110,12 @@ static __inline PVOID GetCurrentFiber(void)
return p;
}
-static __inline struct _TEB * NtCurrentTeb(void)
-{
- struct _TEB *p;
- __asm mov eax, fs:[18h]
- __asm mov [p], eax
- return p;
-}
-
#endif /* _MSC_FULL_VER */
#endif /* __GNUC__/__WATCOMC__/_MSC_VER */
+#include "inline_ntcurrentteb.h"
+
static __inline PVOID GetFiberData(void)
{
return *((PVOID *)GetCurrentFiber());
diff --git a/reactos/ntoskrnl/cache/cachesub.c b/reactos/ntoskrnl/cache/cachesub.c
new file mode 100644
index 00000000000..fb9d9e31eb9
--- /dev/null
+++ b/reactos/ntoskrnl/cache/cachesub.c
@@ -0,0 +1,347 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/cache/cachesup.c
+ * PURPOSE: Logging and configuration routines
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ * Art Yerkes
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include
+#include "newcc.h"
+#include "section/newmm.h"
+#define NDEBUG
+#include
+
+/* STRUCTURES *****************************************************************/
+
+typedef struct _WORK_QUEUE_WITH_READ_AHEAD
+{
+ WORK_QUEUE_ITEM WorkItem;
+ PFILE_OBJECT FileObject;
+ LARGE_INTEGER FileOffset;
+ ULONG Length;
+} WORK_QUEUE_WITH_READ_AHEAD, *PWORK_QUEUE_WITH_READ_AHEAD;
+
+/* FUNCTIONS ******************************************************************/
+
+PDEVICE_OBJECT
+NTAPI
+MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject);
+
+VOID
+NTAPI
+CcSetReadAheadGranularity(IN PFILE_OBJECT FileObject,
+ IN ULONG Granularity)
+{
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+ if (Map)
+ {
+ Map->ReadAheadGranularity = Granularity;
+ }
+}
+
+VOID
+NTAPI
+CcpReadAhead(PVOID Context)
+{
+ LARGE_INTEGER Offset;
+ PWORK_QUEUE_WITH_READ_AHEAD WorkItem = (PWORK_QUEUE_WITH_READ_AHEAD)Context;
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)WorkItem->FileObject->SectionObjectPointer->SharedCacheMap;
+ DPRINT("Reading ahead %08x%08x:%x %wZ\n",
+ WorkItem->FileOffset.HighPart,
+ WorkItem->FileOffset.LowPart,
+ WorkItem->Length,
+ &WorkItem->FileObject->FileName);
+ Offset.HighPart = WorkItem->FileOffset.HighPart;
+ Offset.LowPart = PAGE_ROUND_DOWN(WorkItem->FileOffset.LowPart);
+ if (Map)
+ {
+ PLIST_ENTRY ListEntry;
+ volatile char *chptr;
+ PNOCC_BCB Bcb;
+ for (ListEntry = Map->AssociatedBcb.Flink;
+ ListEntry != &Map->AssociatedBcb;
+ ListEntry = ListEntry->Flink)
+ {
+ Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
+ if ((Offset.QuadPart + WorkItem->Length < Bcb->FileOffset.QuadPart) ||
+ (Bcb->FileOffset.QuadPart + Bcb->Length < Offset.QuadPart))
+ continue;
+ for (chptr = Bcb->BaseAddress, Offset = Bcb->FileOffset;
+ chptr < ((PCHAR)Bcb->BaseAddress) + Bcb->Length &&
+ Offset.QuadPart <
+ WorkItem->FileOffset.QuadPart + WorkItem->Length;
+ chptr += PAGE_SIZE, Offset.QuadPart += PAGE_SIZE)
+ {
+ *chptr ^= 0;
+ }
+ }
+ }
+ ObDereferenceObject(WorkItem->FileObject);
+ ExFreePool(WorkItem);
+ DPRINT("Done\n");
+}
+
+VOID
+NTAPI
+CcScheduleReadAhead(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length)
+{
+ PWORK_QUEUE_WITH_READ_AHEAD WorkItem;
+ DPRINT("Schedule read ahead %08x%08x:%x %wZ\n",
+ FileOffset->HighPart,
+ FileOffset->LowPart,
+ Length,
+ &FileObject->FileName);
+ WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
+ if (!WorkItem) KeBugCheck(0);
+ ObReferenceObject(FileObject);
+ WorkItem->FileObject = FileObject;
+ WorkItem->FileOffset = *FileOffset;
+ WorkItem->Length = Length;
+ ExInitializeWorkItem(((PWORK_QUEUE_ITEM)WorkItem), (PWORKER_THREAD_ROUTINE)CcpReadAhead, WorkItem);
+ ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
+ DPRINT("Done\n");
+}
+
+VOID
+NTAPI
+CcSetDirtyPinnedData(IN PVOID BcbVoid,
+ IN OPTIONAL PLARGE_INTEGER Lsn)
+{
+ PNOCC_BCB Bcb = (PNOCC_BCB)BcbVoid;
+ Bcb->Dirty = TRUE;
+}
+
+LARGE_INTEGER
+NTAPI
+CcGetFlushedValidData(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+ IN BOOLEAN CcInternalCaller)
+{
+ LARGE_INTEGER Result = {{0}};
+ UNIMPLEMENTED;
+ while (TRUE);
+ return Result;
+}
+
+
+
+VOID
+NTAPI
+_CcpFlushCache(IN PNOCC_CACHE_MAP Map,
+ IN OPTIONAL PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ OUT OPTIONAL PIO_STATUS_BLOCK IoStatus,
+ BOOLEAN Delete,
+ const char *File,
+ int Line)
+{
+ PNOCC_BCB Bcb = NULL;
+ LARGE_INTEGER LowerBound, UpperBound;
+ PLIST_ENTRY ListEntry;
+ IO_STATUS_BLOCK IOSB = { };
+
+ DPRINT1("CcFlushCache (while file) (%s:%d)\n", File, Line);
+
+ if (FileOffset && Length)
+ {
+ LowerBound.QuadPart = FileOffset->QuadPart;
+ UpperBound.QuadPart = LowerBound.QuadPart + Length;
+ }
+ else
+ {
+ LowerBound.QuadPart = 0;
+ UpperBound.QuadPart = 0x7fffffffffffffffull;
+ }
+
+ CcpLock();
+ ListEntry = Map->AssociatedBcb.Flink;
+
+ while (ListEntry != &Map->AssociatedBcb)
+ {
+ Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
+ CcpReferenceCache(Bcb - CcCacheSections);
+
+ if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart &&
+ Bcb->FileOffset.QuadPart < UpperBound.QuadPart)
+ {
+ DPRINT
+ ("Bcb #%x (@%08x%08x)\n",
+ Bcb - CcCacheSections,
+ Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart);
+
+ Bcb->RefCount++;
+ CcpUnlock();
+ MiFlushMappedSection(Bcb->BaseAddress, &Bcb->FileOffset, &Map->FileSizes.FileSize, Bcb->Dirty);
+ CcpLock();
+ Bcb->RefCount--;
+
+ Bcb->Dirty = FALSE;
+
+ ListEntry = ListEntry->Flink;
+ if (Delete && Bcb->RefCount < 2)
+ {
+ Bcb->RefCount = 1;
+ CcpDereferenceCache(Bcb - CcCacheSections, FALSE);
+ }
+ else
+ CcpUnpinData(Bcb);
+ }
+ else
+ {
+ ListEntry = ListEntry->Flink;
+ CcpUnpinData(Bcb);
+ }
+
+ DPRINT("End loop\n");
+ }
+ CcpUnlock();
+
+ if (IoStatus) *IoStatus = IOSB;
+}
+
+VOID
+NTAPI
+CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+ IN OPTIONAL PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ OUT OPTIONAL PIO_STATUS_BLOCK IoStatus)
+{
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
+
+ // Not cached
+ if (!Map)
+ {
+ if (IoStatus)
+ {
+ IoStatus->Status = STATUS_SUCCESS;
+ IoStatus->Information = 0;
+ }
+ return;
+ }
+
+ CcpFlushCache(Map, FileOffset, Length, IoStatus, TRUE);
+}
+
+BOOLEAN
+NTAPI
+CcFlushImageSection
+(PSECTION_OBJECT_POINTERS SectionObjectPointer,
+ MMFLUSH_TYPE FlushType)
+{
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
+ PNOCC_BCB Bcb;
+ PLIST_ENTRY Entry;
+ IO_STATUS_BLOCK IOSB;
+ BOOLEAN Result = TRUE;
+
+ if (!Map) return TRUE;
+
+ for (Entry = Map->AssociatedBcb.Flink;
+ Entry != &Map->AssociatedBcb;
+ Entry = Entry->Flink)
+ {
+ Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
+
+ if (!Bcb->Dirty) continue;
+
+ switch (FlushType)
+ {
+ case MmFlushForDelete:
+ CcPurgeCacheSection
+ (SectionObjectPointer,
+ &Bcb->FileOffset,
+ Bcb->Length,
+ FALSE);
+ break;
+ case MmFlushForWrite:
+ CcFlushCache
+ (SectionObjectPointer,
+ &Bcb->FileOffset,
+ Bcb->Length,
+ &IOSB);
+ break;
+ }
+ }
+
+ return Result;
+}
+
+// Always succeeds for us
+PVOID
+NTAPI
+CcRemapBcb(IN PVOID Bcb)
+{
+ CcpLock();
+ ASSERT(RtlTestBit(CcCacheBitmap, ((PNOCC_BCB)Bcb) - CcCacheSections));
+ CcpReferenceCache(((PNOCC_BCB)Bcb) - CcCacheSections);
+ CcpUnlock();
+ return Bcb;
+}
+
+VOID
+NTAPI
+CcShutdownSystem()
+{
+ ULONG i;
+
+ DPRINT1("CC: Shutdown\n");
+
+ for (i = 0; i < CACHE_NUM_SECTIONS; i++)
+ {
+ PNOCC_BCB Bcb = &CcCacheSections[i];
+ if (Bcb->SectionObject)
+ {
+ DPRINT1
+ ("Evicting #%02x %08x%08x %wZ\n",
+ i,
+ Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart,
+ &MmGetFileObjectForSection
+ ((PROS_SECTION_OBJECT)Bcb->SectionObject)->FileName);
+ CcpFlushCache(Bcb->Map, NULL, 0, NULL, TRUE);
+ Bcb->Dirty = FALSE;
+ }
+ }
+
+ DPRINT1("Done\n");
+}
+
+
+VOID
+NTAPI
+CcRepinBcb(IN PVOID Bcb)
+{
+ CcpLock();
+ ASSERT(RtlTestBit(CcCacheBitmap, ((PNOCC_BCB)Bcb) - CcCacheSections));
+ DPRINT("CcRepinBcb(#%x)\n", ((PNOCC_BCB)Bcb) - CcCacheSections);
+ CcpReferenceCache(((PNOCC_BCB)Bcb) - CcCacheSections);
+ CcpUnlock();
+}
+
+VOID
+NTAPI
+CcUnpinRepinnedBcb(IN PVOID Bcb,
+ IN BOOLEAN WriteThrough,
+ OUT PIO_STATUS_BLOCK IoStatus)
+{
+ PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
+
+ if (WriteThrough)
+ {
+ DPRINT("BCB #%x\n", RealBcb - CcCacheSections);
+
+ CcpFlushCache
+ (RealBcb->Map,
+ &RealBcb->FileOffset,
+ RealBcb->Length,
+ IoStatus, RealBcb->Dirty);
+ }
+
+ CcUnpinData(Bcb);
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/copysup.c b/reactos/ntoskrnl/cache/copysup.c
new file mode 100644
index 00000000000..2f8a954e846
--- /dev/null
+++ b/reactos/ntoskrnl/cache/copysup.c
@@ -0,0 +1,214 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/cache/copysup.c
+ * PURPOSE: Logging and configuration routines
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include
+#include "newcc.h"
+#include "section/newmm.h"
+#define NDEBUG
+#include
+
+/* GLOBALS ********************************************************************/
+
+ULONG CcFastMdlReadWait;
+ULONG CcFastMdlReadNotPossible;
+ULONG CcFastReadNotPossible;
+ULONG CcFastReadWait;
+ULONG CcFastReadNoWait;
+ULONG CcFastReadResourceMiss;
+
+#define TAG_COPY_READ TAG('C', 'o', 'p', 'y')
+#define TAG_COPY_WRITE TAG('R', 'i', 't', 'e')
+
+/* FUNCTIONS ******************************************************************/
+
+BOOLEAN
+NTAPI
+CcCopyRead(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus)
+{
+ PCHAR ReadBuffer;
+ ULONG ReadLen;
+ PVOID Bcb;
+ PCHAR BufferTarget = (PCHAR)Buffer;
+ LARGE_INTEGER CacheOffset, EndOfExtent, NextOffset;
+
+ DPRINT
+ ("CcCopyRead(%x,%x,%d,%d,%x)\n",
+ FileObject,
+ FileOffset->LowPart,
+ Length,
+ Wait,
+ Buffer);
+
+ CacheOffset.QuadPart = FileOffset->QuadPart;
+ EndOfExtent.QuadPart = FileOffset->QuadPart + Length;
+
+ while (CacheOffset.QuadPart < EndOfExtent.QuadPart)
+ {
+ NextOffset.QuadPart = CacheOffset.QuadPart;
+ NextOffset.LowPart = (NextOffset.LowPart + CACHE_STRIPE) & ~(CACHE_STRIPE-1);
+ ReadLen = EndOfExtent.QuadPart - CacheOffset.QuadPart;
+ if (CacheOffset.QuadPart + ReadLen > NextOffset.QuadPart)
+ {
+ ReadLen = NextOffset.QuadPart - CacheOffset.QuadPart;
+ }
+
+ DPRINT("Reading %d bytes in this go (at %08x%08x)\n", ReadLen, CacheOffset.HighPart, CacheOffset.LowPart);
+
+ if (!CcPinRead
+ (FileObject,
+ &CacheOffset,
+ ReadLen,
+ Wait ? PIN_WAIT : PIN_IF_BCB,
+ &Bcb,
+ (PVOID*)&ReadBuffer))
+ {
+ IoStatus->Status = STATUS_UNSUCCESSFUL;
+ IoStatus->Information = 0;
+ DPRINT("Failed CcCopyRead\n");
+ return FALSE;
+ }
+
+ DPRINT1("Copying %d bytes at %08x%08x\n", ReadLen, CacheOffset.HighPart, CacheOffset.LowPart);
+ RtlCopyMemory
+ (BufferTarget,
+ ReadBuffer,
+ ReadLen);
+
+ BufferTarget += ReadLen;
+
+ CacheOffset = NextOffset;
+ CcUnpinData(Bcb);
+ }
+
+ IoStatus->Status = STATUS_SUCCESS;
+ IoStatus->Information = Length;
+
+ DPRINT("Done with CcCopyRead\n");
+
+ return TRUE;
+}
+
+VOID
+NTAPI
+CcFastCopyRead(IN PFILE_OBJECT FileObject,
+ IN ULONG FileOffset,
+ IN ULONG Length,
+ IN ULONG PageCount,
+ OUT PVOID Buffer,
+ OUT PIO_STATUS_BLOCK IoStatus)
+{
+ UNIMPLEMENTED;
+ while (TRUE);
+}
+
+BOOLEAN
+NTAPI
+CcCopyWrite(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Wait,
+ IN PVOID Buffer)
+{
+ INT Count = 0;
+ BOOLEAN Result;
+ PNOCC_BCB Bcb;
+ PVOID WriteBuf;
+ ULONG WriteLen;
+ LARGE_INTEGER CurrentOffset = *FileOffset;
+ LARGE_INTEGER EndOffset;
+ LARGE_INTEGER NextOffset;
+
+ EndOffset.QuadPart = CurrentOffset.QuadPart + Length;
+
+ DPRINT
+ ("CcCopyWrite(%x,%x,%d,%d,%x)\n",
+ FileObject,
+ FileOffset->LowPart,
+ Length,
+ Wait,
+ Buffer);
+
+ while (CurrentOffset.QuadPart < EndOffset.QuadPart)
+ {
+ NextOffset.HighPart = CurrentOffset.HighPart;
+ NextOffset.LowPart = (CurrentOffset.LowPart + CACHE_STRIPE) & ~(CACHE_STRIPE - 1);
+ DPRINT("NextOffset %08x%08x\n", NextOffset.u.HighPart, NextOffset.u.LowPart);
+ WriteLen = MIN(NextOffset.QuadPart - CurrentOffset.QuadPart, Length);
+ DPRINT("Copying %x bytes from %08x%08x\n",
+ WriteLen,
+ CurrentOffset.u.HighPart, CurrentOffset.u.LowPart);
+ DPRINT("CcPreparePinWrite\n");
+ Result = CcPreparePinWrite
+ (FileObject, &CurrentOffset, WriteLen, FALSE, Wait ? PIN_WAIT : PIN_IF_BCB,
+ (PVOID *)&Bcb, &WriteBuf);
+ DPRINT("Result %s %x %x\n", Result ? "TRUE" : "FALSE", Bcb, WriteBuf);
+ if (!Result)
+ {
+ DPRINT1("CcPreparePinWrite Failed?\n");
+ if (Wait) RtlRaiseStatus(STATUS_NOT_MAPPED_DATA); else return FALSE;
+ }
+ DPRINT1("Copying actual memory to BCB#%x (@%x) (from buffer at %x)\n", Bcb - CcCacheSections, WriteBuf, Bcb->BaseAddress);
+
+ //MiZeroFillSection(WriteBuf, &CurrentOffset, WriteLen);
+ RtlCopyMemory(WriteBuf, ((PCHAR)Buffer) + Count, WriteLen);
+ Count += WriteLen;
+ Length -= WriteLen;
+ CurrentOffset = NextOffset;
+ Bcb->Dirty = TRUE;
+ CcUnpinData(Bcb);
+ }
+
+ DPRINT("Done with CcCopyWrite\n");
+
+ return TRUE;
+}
+
+VOID
+NTAPI
+CcFastCopyWrite(IN PFILE_OBJECT FileObject,
+ IN ULONG FileOffset,
+ IN ULONG Length,
+ IN PVOID Buffer)
+{
+ UNIMPLEMENTED;
+ while (TRUE);
+}
+
+BOOLEAN
+NTAPI
+CcCanIWrite(IN PFILE_OBJECT FileObject,
+ IN ULONG BytesToWrite,
+ IN BOOLEAN Wait,
+ IN UCHAR Retrying)
+{
+ UNIMPLEMENTED;
+ while (TRUE);
+ return FALSE;
+}
+
+VOID
+NTAPI
+CcDeferWrite(IN PFILE_OBJECT FileObject,
+ IN PCC_POST_DEFERRED_WRITE PostRoutine,
+ IN PVOID Context1,
+ IN PVOID Context2,
+ IN ULONG BytesToWrite,
+ IN BOOLEAN Retrying)
+{
+ UNIMPLEMENTED;
+ while (TRUE);
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/fssup.c b/reactos/ntoskrnl/cache/fssup.c
new file mode 100644
index 00000000000..8646513e3b0
--- /dev/null
+++ b/reactos/ntoskrnl/cache/fssup.c
@@ -0,0 +1,513 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/cache/fssup.c
+ * PURPOSE: Logging and configuration routines
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ * Art Yerkes
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include
+#include "newcc.h"
+#include "section/newmm.h"
+#define NDEBUG
+#include
+
+/* GLOBALS ********************************************************************/
+
+PFSN_PREFETCHER_GLOBALS CcPfGlobals;
+extern LONG CcOutstandingDeletes;
+extern KEVENT CcpLazyWriteEvent;
+extern KEVENT CcFinalizeEvent;
+extern VOID NTAPI CcpUnmapThread(PVOID Unused);
+extern VOID NTAPI CcpLazyWriteThread(PVOID Unused);
+HANDLE CcUnmapThreadHandle, CcLazyWriteThreadHandle;
+CLIENT_ID CcUnmapThreadId, CcLazyWriteThreadId;
+
+typedef struct _NOCC_PRIVATE_CACHE_MAP
+{
+ LIST_ENTRY ListEntry;
+ PFILE_OBJECT FileObject;
+ PNOCC_CACHE_MAP Map;
+} NOCC_PRIVATE_CACHE_MAP, *PNOCC_PRIVATE_CACHE_MAP;
+
+LIST_ENTRY CcpAllSharedCacheMaps;
+
+/* FUNCTIONS ******************************************************************/
+
+// Interact with legacy balance manager for now
+// This can fall away when our section implementation supports
+// demand paging properly
+NTSTATUS
+CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
+{
+ ULONG i, Freed, BcbHead;
+
+ *NrFreed = 0;
+
+ for (i = 0; i < CACHE_NUM_SECTIONS; i++) {
+ BcbHead = (i+CcCacheClockHand) % CACHE_NUM_SECTIONS;
+
+ // Reference a cache stripe so it won't go away
+ CcpLock();
+ if (CcCacheSections[BcbHead].BaseAddress) {
+ CcpReferenceCache(i);
+ CcpUnlock();
+ } else {
+ CcpUnlock();
+ continue;
+ }
+
+ // Defer to MM to try recovering pages from it
+ Freed = MiCacheEvictPages
+ (CcCacheSections[BcbHead].BaseAddress, Target);
+
+ Target -= Freed;
+ *NrFreed += Freed;
+
+ CcpLock();
+ CcpDereferenceCache(BcbHead, FALSE);
+ CcpUnlock();
+ }
+
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN
+NTAPI
+CcInitializeCacheManager(VOID)
+{
+ int i;
+
+ DPRINT("Initialize\n");
+ for (i = 0; i < CACHE_NUM_SECTIONS; i++)
+ {
+ KeInitializeEvent(&CcCacheSections[i].ExclusiveWait, SynchronizationEvent, FALSE);
+ InitializeListHead(&CcCacheSections[i].ThisFileList);
+ }
+
+ InitializeListHead(&CcpAllSharedCacheMaps);
+
+ KeInitializeEvent(&CcDeleteEvent, SynchronizationEvent, FALSE);
+ KeInitializeEvent(&CcFinalizeEvent, SynchronizationEvent, FALSE);
+ KeInitializeEvent(&CcpLazyWriteEvent, SynchronizationEvent, FALSE);
+
+ CcCacheBitmap->Buffer = ((PULONG)&CcCacheBitmap[1]);
+ CcCacheBitmap->SizeOfBitMap = ROUND_UP(CACHE_NUM_SECTIONS, 32);
+ DPRINT("Cache has %d entries\n", CcCacheBitmap->SizeOfBitMap);
+ ExInitializeFastMutex(&CcMutex);
+
+ // MM stub
+ KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
+
+ // Until we're fully demand paged, we can do things the old way through
+ // the balance manager
+ MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
+
+ return TRUE;
+}
+
+VOID
+NTAPI
+CcPfInitializePrefetcher(VOID)
+{
+ /* Notify debugger */
+ DbgPrintEx(DPFLTR_PREFETCHER_ID,
+ DPFLTR_TRACE_LEVEL,
+ "CCPF: InitializePrefetecher()\n");
+
+ /* Setup the Prefetcher Data */
+ InitializeListHead(&CcPfGlobals.ActiveTraces);
+ InitializeListHead(&CcPfGlobals.CompletedTraces);
+ ExInitializeFastMutex(&CcPfGlobals.CompletedTracesLock);
+
+ /* FIXME: Setup the rest of the prefetecher */
+}
+
+BOOLEAN
+NTAPI
+CcpAcquireFileLock(PNOCC_CACHE_MAP Map)
+{
+ DPRINT("Calling AcquireForLazyWrite: %x\n", Map->LazyContext);
+ return Map->Callbacks.AcquireForLazyWrite(Map->LazyContext, TRUE);
+}
+
+VOID
+NTAPI
+CcpReleaseFileLock(PNOCC_CACHE_MAP Map)
+{
+ DPRINT("Releasing Lazy Write %x\n", Map->LazyContext);
+ Map->Callbacks.ReleaseFromLazyWrite(Map->LazyContext);
+}
+
+// Must have CcpLock()
+PFILE_OBJECT CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject)
+{
+ PLIST_ENTRY Entry, Private;
+ for (Entry = CcpAllSharedCacheMaps.Flink;
+ Entry != &CcpAllSharedCacheMaps;
+ Entry = Entry->Flink)
+ {
+ // 'Identical' test for other stream file object
+ PNOCC_CACHE_MAP Map = CONTAINING_RECORD(Entry, NOCC_CACHE_MAP, Entry);
+ for (Private = Map->PrivateCacheMaps.Flink;
+ Private != &Map->PrivateCacheMaps;
+ Private = Private->Flink)
+ {
+ PNOCC_PRIVATE_CACHE_MAP PrivateMap = CONTAINING_RECORD(Private, NOCC_PRIVATE_CACHE_MAP, ListEntry);
+ if (PrivateMap->FileObject->Flags & FO_STREAM_FILE &&
+ PrivateMap->FileObject->DeviceObject == FileObject->DeviceObject &&
+ PrivateMap->FileObject->Vpb == FileObject->Vpb &&
+ PrivateMap->FileObject->FsContext == FileObject->FsContext &&
+ PrivateMap->FileObject->FsContext2 == FileObject->FsContext2 &&
+ 1)
+ {
+ return PrivateMap->FileObject;
+ }
+ }
+ }
+ return 0;
+}
+
+// Thanks: http://windowsitpro.com/Windows/Articles/ArticleID/3864/pg/2/2.html
+
+VOID
+NTAPI
+CcInitializeCacheMap(IN PFILE_OBJECT FileObject,
+ IN PCC_FILE_SIZES FileSizes,
+ IN BOOLEAN PinAccess,
+ IN PCACHE_MANAGER_CALLBACKS Callbacks,
+ IN PVOID LazyWriteContext)
+{
+ PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
+ PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
+
+ CcpLock();
+ if (!Map && FileObject->Flags & FO_STREAM_FILE)
+ {
+ PFILE_OBJECT IdenticalStreamFileObject =
+ CcpFindOtherStreamFileObject(FileObject);
+ if (IdenticalStreamFileObject)
+ Map = IdenticalStreamFileObject->SectionObjectPointer->SharedCacheMap;
+ if (Map)
+ {
+ DPRINT1
+ ("Linking SFO %x to previous SFO %x through cache map %x #\n",
+ FileObject, IdenticalStreamFileObject, Map);
+ }
+ }
+ if (!Map)
+ {
+ DPRINT("Initializing file object for (%p) %wZ\n", FileObject, &FileObject->FileName);
+ Map = ExAllocatePool(NonPagedPool, sizeof(NOCC_CACHE_MAP));
+ FileObject->SectionObjectPointer->SharedCacheMap = Map;
+ Map->FileSizes = *FileSizes;
+ Map->LazyContext = LazyWriteContext;
+ Map->ReadAheadGranularity = PAGE_SIZE;
+ RtlCopyMemory(&Map->Callbacks, Callbacks, sizeof(*Callbacks));
+ // For now ...
+ DPRINT("FileSizes->ValidDataLength %08x%08x\n", FileSizes->ValidDataLength.HighPart, FileSizes->ValidDataLength.LowPart);
+ InitializeListHead(&Map->AssociatedBcb);
+ InitializeListHead(&Map->PrivateCacheMaps);
+ InsertTailList(&CcpAllSharedCacheMaps, &Map->Entry);
+ DPRINT("New Map %x\n", Map);
+ }
+ if (!PrivateCacheMap)
+ {
+ PrivateCacheMap = ExAllocatePool(NonPagedPool, sizeof(*PrivateCacheMap));
+ FileObject->PrivateCacheMap = PrivateCacheMap;
+ PrivateCacheMap->FileObject = FileObject;
+ ObReferenceObject(PrivateCacheMap->FileObject);
+ }
+
+ PrivateCacheMap->Map = Map;
+ InsertTailList(&Map->PrivateCacheMaps, &PrivateCacheMap->ListEntry);
+
+ CcpUnlock();
+}
+
+ULONG
+NTAPI
+CcpCountCacheSections(IN PNOCC_CACHE_MAP Map)
+{
+ PLIST_ENTRY Entry;
+ ULONG Count;
+
+ for (Count = 0, Entry = Map->AssociatedBcb.Flink; Entry != &Map->AssociatedBcb; Entry = Entry->Flink, Count++);
+
+ return Count;
+}
+
+BOOLEAN
+NTAPI
+CcUninitializeCacheMap(IN PFILE_OBJECT FileObject,
+ IN OPTIONAL PLARGE_INTEGER TruncateSize,
+ IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
+{
+ BOOLEAN LastMap = FALSE;
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+ PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
+
+ DPRINT("Uninitializing file object for %wZ SectionObjectPointer %x\n", &FileObject->FileName, FileObject->SectionObjectPointer);
+
+ ASSERT(UninitializeEvent == NULL);
+
+ if (Map)
+ CcpFlushCache(Map, NULL, 0, NULL, FALSE);
+
+ CcpLock();
+ if (PrivateCacheMap)
+ {
+ ASSERT(!Map || Map == PrivateCacheMap->Map);
+ ASSERT(PrivateCacheMap->FileObject == FileObject);
+
+ RemoveEntryList(&PrivateCacheMap->ListEntry);
+ if (IsListEmpty(&PrivateCacheMap->Map->PrivateCacheMaps))
+ {
+ while (!IsListEmpty(&Map->AssociatedBcb))
+ {
+ PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
+ DPRINT("Evicting cache stripe #%x\n", Bcb - CcCacheSections);
+ Bcb->RefCount = 1;
+ CcpDereferenceCache(Bcb - CcCacheSections, TRUE);
+ }
+ RemoveEntryList(&PrivateCacheMap->Map->Entry);
+ ExFreePool(PrivateCacheMap->Map);
+ FileObject->SectionObjectPointer->SharedCacheMap = NULL;
+ LastMap = TRUE;
+ }
+ ObDereferenceObject(PrivateCacheMap->FileObject);
+ FileObject->PrivateCacheMap = NULL;
+ ExFreePool(PrivateCacheMap);
+ }
+ CcpUnlock();
+
+ DPRINT("Uninit complete\n");
+
+ return LastMap;
+}
+
+VOID
+NTAPI
+CcSetFileSizes(IN PFILE_OBJECT FileObject,
+ IN PCC_FILE_SIZES FileSizes)
+{
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+ if (!Map) return;
+ Map->FileSizes = *FileSizes;
+ PNOCC_BCB Bcb = Map->AssociatedBcb.Flink == &Map->AssociatedBcb ?
+ NULL : CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
+ if (!Bcb) return;
+ MmExtendCacheSection(Bcb->SectionObject, &FileSizes->FileSize, FALSE);
+ DPRINT("FileSizes->FileSize %x\n", FileSizes->FileSize.LowPart);
+ DPRINT("FileSizes->AllocationSize %x\n", FileSizes->AllocationSize.LowPart);
+ DPRINT("FileSizes->ValidDataLength %x\n", FileSizes->ValidDataLength.LowPart);
+}
+
+BOOLEAN
+NTAPI
+CcGetFileSizes
+(IN PFILE_OBJECT FileObject,
+ IN PCC_FILE_SIZES FileSizes)
+{
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+ if (!Map) return FALSE;
+ *FileSizes = Map->FileSizes;
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
+ IN OPTIONAL PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN UninitializeCacheMaps)
+{
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
+ if (!Map) return TRUE;
+ CcpFlushCache(Map, NULL, 0, NULL, TRUE);
+ return TRUE;
+}
+
+VOID
+NTAPI
+CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject,
+ IN ULONG DirtyPageThreshold)
+{
+ UNIMPLEMENTED;
+ while (TRUE);
+}
+
+BOOLEAN
+NTAPI
+CcZeroData(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER StartOffset,
+ IN PLARGE_INTEGER EndOffset,
+ IN BOOLEAN Wait)
+{
+ PNOCC_BCB Bcb = NULL;
+ PLIST_ENTRY ListEntry = NULL;
+ LARGE_INTEGER LowerBound = *StartOffset;
+ LARGE_INTEGER UpperBound = *EndOffset;
+ LARGE_INTEGER Target, End;
+ PVOID PinnedBcb, PinnedBuffer;
+ PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
+
+ DPRINT
+ ("S %08x%08x E %08x%08x\n",
+ StartOffset->u.HighPart, StartOffset->u.LowPart,
+ EndOffset->u.HighPart, EndOffset->u.LowPart);
+
+ if (!Map)
+ {
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IOSB;
+ PCHAR ZeroBuf = ExAllocatePool(PagedPool, PAGE_SIZE);
+ ULONG ToWrite;
+
+ if (!ZeroBuf) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
+ RtlZeroMemory(ZeroBuf, PAGE_SIZE);
+
+ Target.QuadPart = PAGE_ROUND_DOWN(LowerBound.QuadPart);
+ End.QuadPart = PAGE_ROUND_UP(UpperBound.QuadPart);
+
+ // Handle leading page
+ if (LowerBound.QuadPart != Target.QuadPart)
+ {
+ ToWrite = MIN(UpperBound.QuadPart - LowerBound.QuadPart, (PAGE_SIZE - LowerBound.QuadPart) & (PAGE_SIZE - 1));
+ DPRINT("Zero last half %08x%08x %x\n", Target.u.HighPart, Target.u.LowPart, ToWrite);
+ Status = MiSimpleRead(FileObject, &Target, ZeroBuf, PAGE_SIZE, &IOSB);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(ZeroBuf);
+ RtlRaiseStatus(Status);
+ }
+ DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf + LowerBound.QuadPart - Target.QuadPart, ToWrite);
+ RtlZeroMemory(ZeroBuf + LowerBound.QuadPart - Target.QuadPart, ToWrite);
+ Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, MIN(PAGE_SIZE,UpperBound.QuadPart-Target.QuadPart), &IOSB);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(ZeroBuf);
+ RtlRaiseStatus(Status);
+ }
+ Target.QuadPart += PAGE_SIZE;
+ }
+
+ DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
+ RtlZeroMemory(ZeroBuf, PAGE_SIZE);
+
+ while (UpperBound.QuadPart - Target.QuadPart > PAGE_SIZE)
+ {
+ DPRINT("Zero full page %08x%08x\n", Target.u.HighPart, Target.u.LowPart);
+ Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, PAGE_SIZE, &IOSB);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(ZeroBuf);
+ RtlRaiseStatus(Status);
+ }
+ Target.QuadPart += PAGE_SIZE;
+ }
+
+ if (UpperBound.QuadPart > Target.QuadPart)
+ {
+ ToWrite = UpperBound.QuadPart - Target.QuadPart;
+ DPRINT("Zero first half %08x%08x %x\n", Target.u.HighPart, Target.u.LowPart, ToWrite);
+ Status = MiSimpleRead(FileObject, &Target, ZeroBuf, PAGE_SIZE, &IOSB);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(ZeroBuf);
+ RtlRaiseStatus(Status);
+ }
+ DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, ToWrite);
+ RtlZeroMemory(ZeroBuf, ToWrite);
+ Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, MIN(PAGE_SIZE, UpperBound.QuadPart-Target.QuadPart), &IOSB);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(ZeroBuf);
+ RtlRaiseStatus(Status);
+ }
+ Target.QuadPart += PAGE_SIZE;
+ }
+
+ ExFreePool(ZeroBuf);
+ return TRUE;
+ }
+
+ CcpLock();
+ ListEntry = Map->AssociatedBcb.Flink;
+
+ while (ListEntry != &Map->AssociatedBcb)
+ {
+ Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
+ CcpReferenceCache(Bcb - CcCacheSections);
+
+ if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart &&
+ Bcb->FileOffset.QuadPart < UpperBound.QuadPart)
+ {
+ DPRINT
+ ("Bcb #%x (@%08x%08x)\n",
+ Bcb - CcCacheSections,
+ Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart);
+
+ Target.QuadPart = MAX(Bcb->FileOffset.QuadPart, LowerBound.QuadPart);
+ End.QuadPart = MIN(Map->FileSizes.ValidDataLength.QuadPart, UpperBound.QuadPart);
+ End.QuadPart = MIN(End.QuadPart, Bcb->FileOffset.QuadPart + Bcb->Length);
+ CcpUnlock();
+
+ if (!CcPreparePinWrite
+ (FileObject,
+ &Target,
+ End.QuadPart - Target.QuadPart,
+ TRUE,
+ Wait,
+ &PinnedBcb,
+ &PinnedBuffer))
+ {
+ return FALSE;
+ }
+
+ ASSERT(PinnedBcb == Bcb);
+
+ CcpLock();
+ ListEntry = ListEntry->Flink;
+ // Return from pin state
+ CcpUnpinData(PinnedBcb);
+ }
+
+ CcpUnpinData(Bcb);
+ }
+
+ CcpUnlock();
+
+ return TRUE;
+}
+
+PFILE_OBJECT
+NTAPI
+CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)
+{
+ PFILE_OBJECT Result = NULL;
+ PNOCC_CACHE_MAP Map = SectionObjectPointer->SharedCacheMap;
+ CcpLock();
+ if (!IsListEmpty(&Map->AssociatedBcb))
+ {
+ PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
+ Result = MmGetFileObjectForSection((PROS_SECTION_OBJECT)Bcb->SectionObject);
+ }
+ CcpUnlock();
+ return Result;
+}
+
+PFILE_OBJECT
+NTAPI
+CcGetFileObjectFromBcb(PVOID Bcb)
+{
+ PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
+ DPRINT("BCB #%x\n", RealBcb - CcCacheSections);
+ return MmGetFileObjectForSection((PROS_SECTION_OBJECT)RealBcb->SectionObject);
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/lazyrite.c b/reactos/ntoskrnl/cache/lazyrite.c
new file mode 100644
index 00000000000..4dcbb5d8a36
--- /dev/null
+++ b/reactos/ntoskrnl/cache/lazyrite.c
@@ -0,0 +1,36 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/cache/lazyrite.c
+ * PURPOSE: Logging and configuration routines
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include
+#include "newcc.h"
+#define NDEBUG
+#include
+
+/* GLOBALS ********************************************************************/
+
+KEVENT CcpLazyWriteEvent;
+
+/* FUNCTIONS ******************************************************************/
+
+VOID NTAPI
+CcpLazyWriteThread(PVOID Unused)
+{
+ /* Not implemented */
+}
+
+NTSTATUS
+NTAPI
+CcWaitForCurrentLazyWriterActivity(VOID)
+{
+ //KeWaitForSingleObject(&CcpLazyWriteEvent, Executive, KernelMode, FALSE, NULL);
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/logsup.c b/reactos/ntoskrnl/cache/logsup.c
new file mode 100644
index 00000000000..b06432fc394
--- /dev/null
+++ b/reactos/ntoskrnl/cache/logsup.c
@@ -0,0 +1,75 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/cache/logsup.c
+ * PURPOSE: Logging and configuration routines
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include
+#include "newcc.h"
+#define NDEBUG
+#include
+
+/* GLOBALS ********************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+
+VOID
+NTAPI
+CcSetAdditionalCacheAttributes(IN PFILE_OBJECT FileObject,
+ IN BOOLEAN DisableReadAhead,
+ IN BOOLEAN DisableWriteBehind)
+{
+ UNIMPLEMENTED;
+ while (TRUE);
+}
+
+VOID
+NTAPI
+CcSetLogHandleForFile(IN PFILE_OBJECT FileObject,
+ IN PVOID LogHandle,
+ IN PFLUSH_TO_LSN FlushToLsnRoutine)
+{
+ PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
+ if (!Map) return;
+ Map->LogHandle = LogHandle;
+ Map->FlushToLsn = FlushToLsnRoutine;
+}
+
+LARGE_INTEGER
+NTAPI
+CcGetDirtyPages(IN PVOID LogHandle,
+ IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,
+ IN PVOID Context1,
+ IN PVOID Context2)
+{
+ LARGE_INTEGER Result = {{0}};
+ UNIMPLEMENTED;
+ while (TRUE);
+ return Result;
+}
+
+BOOLEAN
+NTAPI
+CcIsThereDirtyData(IN PVPB Vpb)
+{
+ UNIMPLEMENTED;
+ while (TRUE);
+ return FALSE;
+}
+
+LARGE_INTEGER
+NTAPI
+CcGetLsnForFileObject(IN PFILE_OBJECT FileObject,
+ OUT OPTIONAL PLARGE_INTEGER OldestLsn)
+{
+ LARGE_INTEGER Result = {{0}};
+ UNIMPLEMENTED;
+ while (TRUE);
+ return Result;
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/mdlsup.c b/reactos/ntoskrnl/cache/mdlsup.c
new file mode 100644
index 00000000000..6e558d5aa4c
--- /dev/null
+++ b/reactos/ntoskrnl/cache/mdlsup.c
@@ -0,0 +1,143 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/cache/logsup.c
+ * PURPOSE: Logging and configuration routines
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include
+#include "newcc.h"
+#define NDEBUG
+#include
+
+/* GLOBALS ********************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+
+
+PMDL
+NTAPI
+CcpBuildCacheMdl
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ ULONG Length,
+ PIO_STATUS_BLOCK IOSB)
+{
+ PMDL Mdl;
+ PVOID Bcb, Buffer;
+
+ BOOLEAN Result = CcMapData
+ (FileObject,
+ FileOffset,
+ Length,
+ PIN_WAIT,
+ &Bcb,
+ &Buffer);
+
+ if (!Result)
+ {
+ IOSB->Information = 0;
+ IOSB->Status = STATUS_UNSUCCESSFUL;
+ return NULL;
+ }
+
+ IOSB->Information = Length;
+ IOSB->Status = STATUS_SUCCESS;
+
+ Mdl = IoAllocateMdl
+ (Buffer,
+ Length,
+ FALSE,
+ FALSE,
+ NULL);
+
+ if (!Mdl)
+ {
+ IOSB->Information = 0;
+ IOSB->Status = STATUS_NO_MEMORY;
+ return NULL;
+ }
+
+ IOSB->Information = Length;
+ IOSB->Status = STATUS_SUCCESS;
+
+ return Mdl;
+}
+
+VOID
+NTAPI
+CcMdlRead(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ OUT PMDL *MdlChain,
+ OUT PIO_STATUS_BLOCK IoStatus)
+{
+ *MdlChain = CcpBuildCacheMdl
+ (FileObject,
+ FileOffset,
+ Length,
+ IoStatus);
+}
+
+VOID
+NTAPI
+CcMdlReadComplete(IN PFILE_OBJECT FileObject,
+ IN PMDL MdlChain)
+{
+ IoFreeMdl(MdlChain);
+}
+
+VOID
+NTAPI
+CcMdlReadComplete2(IN PMDL MdlChain,
+ IN PFILE_OBJECT FileObject)
+{
+ DPRINT("Not sure\n");
+}
+
+VOID
+NTAPI
+CcPrepareMdlWrite(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ OUT PMDL *MdlChain,
+ OUT PIO_STATUS_BLOCK IoStatus)
+{
+ *MdlChain = CcpBuildCacheMdl
+ (FileObject,
+ FileOffset,
+ Length,
+ IoStatus);
+}
+
+VOID
+NTAPI
+CcMdlWriteComplete(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN PMDL MdlChain)
+{
+ IoFreeMdl(MdlChain);
+}
+
+VOID
+NTAPI
+CcMdlWriteComplete2(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN PMDL MdlChain)
+{
+ DPRINT("Not sure\n");
+}
+
+VOID
+NTAPI
+CcMdlWriteAbort(IN PFILE_OBJECT FileObject,
+ IN PMDL MdlChain)
+{
+ ASSERT(FALSE);
+ IoFreeMdl(MdlChain);
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/newcc.h b/reactos/ntoskrnl/cache/newcc.h
new file mode 100644
index 00000000000..5e0bd2608eb
--- /dev/null
+++ b/reactos/ntoskrnl/cache/newcc.h
@@ -0,0 +1,170 @@
+#pragma once
+
+struct _MM_CACHE_SECTION_SEGMENT;
+
+typedef struct _NOCC_BCB
+{
+ /* Public part */
+ PUBLIC_BCB Bcb;
+
+ struct _NOCC_CACHE_MAP *Map;
+ struct _MM_CACHE_SECTION_SEGMENT *SectionObject;
+ LARGE_INTEGER FileOffset;
+ ULONG Length;
+ PVOID BaseAddress;
+ BOOLEAN Dirty;
+ PVOID OwnerPointer;
+
+ /* Reference counts */
+ ULONG RefCount;
+
+ LIST_ENTRY ThisFileList;
+
+ KEVENT ExclusiveWait;
+ ULONG ExclusiveWaiter;
+ BOOLEAN Exclusive;
+} NOCC_BCB, *PNOCC_BCB;
+
+typedef struct _NOCC_CACHE_MAP
+{
+ LIST_ENTRY Entry;
+ LIST_ENTRY AssociatedBcb;
+ LIST_ENTRY PrivateCacheMaps;
+ ULONG NumberOfMaps;
+ ULONG RefCount;
+ CC_FILE_SIZES FileSizes;
+ CACHE_MANAGER_CALLBACKS Callbacks;
+ PVOID LazyContext;
+ PVOID LogHandle;
+ PFLUSH_TO_LSN FlushToLsn;
+ ULONG ReadAheadGranularity;
+} NOCC_CACHE_MAP, *PNOCC_CACHE_MAP;
+
+VOID
+NTAPI
+CcPfInitializePrefetcher(
+ VOID
+);
+
+VOID
+NTAPI
+CcMdlReadComplete2(
+ IN PMDL MemoryDescriptorList,
+ IN PFILE_OBJECT FileObject
+);
+
+VOID
+NTAPI
+CcMdlWriteComplete2(
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN PMDL MdlChain
+);
+
+VOID
+NTAPI
+CcInitView(VOID);
+
+VOID
+NTAPI
+CcpUnpinData(PNOCC_BCB Bcb);
+
+BOOLEAN
+NTAPI
+CcInitializeCacheManager(VOID);
+
+VOID
+NTAPI
+CcShutdownSystem();
+
+VOID
+NTAPI
+CcInitCacheZeroPage(VOID);
+
+/* Called by section.c */
+BOOLEAN
+NTAPI
+CcFlushImageSection(PSECTION_OBJECT_POINTERS SectionObjectPointer, MMFLUSH_TYPE FlushType);
+
+VOID
+NTAPI
+_CcpFlushCache
+(IN PNOCC_CACHE_MAP Map,
+ IN OPTIONAL PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ OUT OPTIONAL PIO_STATUS_BLOCK IoStatus,
+ BOOLEAN Delete,
+ const char *File,
+ int Line);
+
+#define CcpFlushCache(M,F,L,I,D) _CcpFlushCache(M,F,L,I,D,__FILE__,__LINE__)
+
+BOOLEAN
+NTAPI
+CcGetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes);
+
+ULONG
+NTAPI
+CcpCountCacheSections(PNOCC_CACHE_MAP Map);
+
+BOOLEAN
+NTAPI
+CcpAcquireFileLock(PNOCC_CACHE_MAP Map);
+
+VOID
+NTAPI
+CcpReleaseFileLock(PNOCC_CACHE_MAP Map);
+
+/*
+ * Macro for generic cache manage bugchecking. Note that this macro assumes
+ * that the file name including extension is always longer than 4 characters.
+ */
+#define KEBUGCHECKCC \
+ KEBUGCHECKEX(CACHE_MANAGER, \
+ (*(ULONG*)(__FILE__ + sizeof(__FILE__) - 4) << 16) | \
+ (__LINE__ & 0xFFFF), 0, 0, 0)
+
+/* Private data */
+
+#define CACHE_SINGLE_FILE_MAX (16)
+#define CACHE_OVERALL_SIZE (32 * 1024 * 1024)
+#define CACHE_STRIPE VACB_MAPPING_GRANULARITY
+#define CACHE_SHIFT 18
+#define CACHE_NUM_SECTIONS (CACHE_OVERALL_SIZE / CACHE_STRIPE)
+#define CACHE_ROUND_UP(x) (((x) + (CACHE_STRIPE-1)) & ~(CACHE_STRIPE-1))
+#define CACHE_ROUND_DOWN(x) ((x) & ~(CACHE_STRIPE-1))
+#define INVALID_CACHE ((ULONG)~0)
+
+extern NOCC_BCB CcCacheSections[CACHE_NUM_SECTIONS];
+extern PRTL_BITMAP CcCacheBitmap;
+extern FAST_MUTEX CcMutex;
+extern KEVENT CcDeleteEvent;
+extern ULONG CcCacheClockHand;
+extern LIST_ENTRY CcPendingUnmap;
+extern KEVENT CcpLazyWriteEvent;
+
+#define CcpLock() _CcpLock(__FILE__,__LINE__)
+#define CcpUnlock() _CcpUnlock(__FILE__,__LINE__)
+
+extern VOID _CcpLock(const char *file, int line);
+extern VOID _CcpUnlock(const char *file, int line);
+
+extern VOID CcpReferenceCache(ULONG Sector);
+extern VOID CcpDereferenceCache(ULONG Sector, BOOLEAN Immediate);
+BOOLEAN
+NTAPI
+CcpMapData
+(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ OUT PVOID *BcbResult,
+ OUT PVOID *Buffer);
+
+BOOLEAN
+NTAPI
+CcpPinMappedData(IN PNOCC_CACHE_MAP Map,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ IN OUT PVOID *Bcb);
diff --git a/reactos/ntoskrnl/cache/pinsup.c b/reactos/ntoskrnl/cache/pinsup.c
new file mode 100644
index 00000000000..5531bbb9720
--- /dev/null
+++ b/reactos/ntoskrnl/cache/pinsup.c
@@ -0,0 +1,785 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/cache/pinsup.c
+ * PURPOSE: Logging and configuration routines
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+ * Art Yerkes
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include
+#include "newcc.h"
+#include "section/newmm.h"
+#define NDEBUG
+#include
+
+/* The following is a test mode that only works with modified filesystems.
+ * it maps the cache sections read only until they're pinned writable, and then
+ * turns them readonly again when they're unpinned.
+ * This helped me determine that a certain bug was not a memory overwrite. */
+//#define PIN_WRITE_ONLY
+
+/* GLOBALS ********************************************************************/
+
+#define TAG_MAP_SEC TAG('C', 'c', 'S', 'x')
+#define TAG_MAP_READ TAG('M', 'c', 'p', 'y')
+#define TAG_MAP_BCB TAG('B', 'c', 'b', ' ')
+
+NOCC_BCB CcCacheSections[CACHE_NUM_SECTIONS];
+CHAR CcpBitmapBuffer[sizeof(RTL_BITMAP) + ROUND_UP((CACHE_NUM_SECTIONS), 32) / 8];
+PRTL_BITMAP CcCacheBitmap = (PRTL_BITMAP)&CcpBitmapBuffer;
+FAST_MUTEX CcMutex;
+KEVENT CcDeleteEvent;
+KEVENT CcFinalizeEvent;
+ULONG CcCacheClockHand;
+LONG CcOutstandingDeletes;
+
+/* FUNCTIONS ******************************************************************/
+
+PETHREAD LastThread;
+VOID _CcpLock(const char *file, int line)
+{
+ //DPRINT("<<<---<<< CC In Mutex(%s:%d %x)!\n", file, line, PsGetCurrentThread());
+ ExAcquireFastMutex(&CcMutex);
+}
+
+VOID _CcpUnlock(const char *file, int line)
+{
+ ExReleaseFastMutex(&CcMutex);
+ //DPRINT(">>>--->>> CC Exit Mutex!\n", file, line);
+}
+
+PDEVICE_OBJECT
+NTAPI
+MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject);
+
+NTSTATUS CcpAllocateSection
+(PFILE_OBJECT FileObject,
+ ULONG Length,
+ ULONG Protect,
+ PMM_CACHE_SECTION_SEGMENT *Result)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER MaxSize;
+
+ MaxSize.QuadPart = Length;
+
+ DPRINT("Making Section for File %x\n", FileObject);
+ DPRINT("File name %wZ\n", &FileObject->FileName);
+ Status = MmCreateCacheSection
+ (Result,
+ STANDARD_RIGHTS_REQUIRED,
+ NULL,
+ &MaxSize,
+ Protect,
+ SEC_RESERVE | SEC_CACHE,
+ FileObject);
+
+ return Status;
+}
+
+typedef struct _WORK_QUEUE_WITH_CONTEXT
+{
+ WORK_QUEUE_ITEM WorkItem;
+ PVOID ToUnmap;
+ LARGE_INTEGER FileOffset;
+ LARGE_INTEGER MapSize;
+ PMM_CACHE_SECTION_SEGMENT ToDeref;
+ PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite;
+ PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite;
+ PVOID LazyContext;
+ BOOLEAN Dirty;
+} WORK_QUEUE_WITH_CONTEXT, *PWORK_QUEUE_WITH_CONTEXT;
+
+VOID
+CcpUnmapCache(PVOID Context)
+{
+ PWORK_QUEUE_WITH_CONTEXT WorkItem = (PWORK_QUEUE_WITH_CONTEXT)Context;
+ DPRINT("Unmapping (finally) %x\n", WorkItem->ToUnmap);
+ WorkItem->AcquireForLazyWrite(WorkItem->LazyContext, TRUE);
+ MiFlushMappedSection(WorkItem->ToUnmap, &WorkItem->FileOffset, &WorkItem->MapSize, WorkItem->Dirty);
+ WorkItem->ReleaseFromLazyWrite(WorkItem->LazyContext);
+ MmUnmapCacheViewInSystemSpace(WorkItem->ToUnmap);
+ MmFinalizeSegment(WorkItem->ToDeref);
+ ExFreePool(WorkItem);
+ DPRINT("Done\n");
+}
+
+/* Must have acquired the mutex */
+VOID CcpDereferenceCache(ULONG Start, BOOLEAN Immediate)
+{
+ PVOID ToUnmap;
+ PNOCC_BCB Bcb;
+ BOOLEAN Dirty;
+ LARGE_INTEGER MappedSize;
+ LARGE_INTEGER BaseOffset;
+ PWORK_QUEUE_WITH_CONTEXT WorkItem;
+
+ DPRINT("CcpDereferenceCache(#%x)\n", Start);
+
+ Bcb = &CcCacheSections[Start];
+
+ Dirty = Bcb->Dirty;
+ ToUnmap = Bcb->BaseAddress;
+ BaseOffset = Bcb->FileOffset;
+ MappedSize = Bcb->Map->FileSizes.ValidDataLength;
+
+ DPRINT("Dereference #%x (count %d)\n", Start, Bcb->RefCount);
+ ASSERT(Bcb->SectionObject);
+ ASSERT(Bcb->RefCount == 1);
+
+ DPRINT("Firing work item for %x\n", Bcb->BaseAddress);
+
+ if (Immediate)
+ {
+ PMM_CACHE_SECTION_SEGMENT ToDeref = Bcb->SectionObject;
+ BOOLEAN Dirty = Bcb->Dirty;
+
+ Bcb->Map = NULL;
+ Bcb->SectionObject = NULL;
+ Bcb->BaseAddress = NULL;
+ Bcb->FileOffset.QuadPart = 0;
+ Bcb->Length = 0;
+ Bcb->RefCount = 0;
+ Bcb->Dirty = FALSE;
+ RemoveEntryList(&Bcb->ThisFileList);
+
+ CcpUnlock();
+ MiFlushMappedSection(ToUnmap, &BaseOffset, &MappedSize, Dirty);
+ MmUnmapCacheViewInSystemSpace(ToUnmap);
+ MmFinalizeSegment(ToDeref);
+ CcpLock();
+ }
+ else
+ {
+ WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
+ if (!WorkItem) KeBugCheck(0);
+ WorkItem->ToUnmap = Bcb->BaseAddress;
+ WorkItem->FileOffset = Bcb->FileOffset;
+ WorkItem->Dirty = Bcb->Dirty;
+ WorkItem->MapSize = MappedSize;
+ WorkItem->ToDeref = Bcb->SectionObject;
+ WorkItem->AcquireForLazyWrite = Bcb->Map->Callbacks.AcquireForLazyWrite;
+ WorkItem->ReleaseFromLazyWrite = Bcb->Map->Callbacks.ReleaseFromLazyWrite;
+ WorkItem->LazyContext = Bcb->Map->LazyContext;
+
+ ExInitializeWorkItem(((PWORK_QUEUE_ITEM)WorkItem), (PWORKER_THREAD_ROUTINE)CcpUnmapCache, WorkItem);
+
+ Bcb->Map = NULL;
+ Bcb->SectionObject = NULL;
+ Bcb->BaseAddress = NULL;
+ Bcb->FileOffset.QuadPart = 0;
+ Bcb->Length = 0;
+ Bcb->RefCount = 0;
+ Bcb->Dirty = FALSE;
+ RemoveEntryList(&Bcb->ThisFileList);
+
+ CcpUnlock();
+ ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
+ CcpLock();
+ }
+ DPRINT("Done\n");
+}
+
+/* Needs mutex */
+ULONG CcpAllocateCacheSections
+(PFILE_OBJECT FileObject,
+ PMM_CACHE_SECTION_SEGMENT SectionObject)
+{
+ ULONG i = INVALID_CACHE;
+ PNOCC_CACHE_MAP Map;
+ PNOCC_BCB Bcb;
+
+ DPRINT("AllocateCacheSections: FileObject %x\n", FileObject);
+
+ if (!FileObject->SectionObjectPointer)
+ return INVALID_CACHE;
+
+ Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+
+ if (!Map)
+ return INVALID_CACHE;
+
+ DPRINT("Allocating Cache Section\n");
+
+ i = RtlFindClearBitsAndSet(CcCacheBitmap, 1, CcCacheClockHand);
+ CcCacheClockHand = (i + 1) % CACHE_NUM_SECTIONS;
+
+ if (i != INVALID_CACHE)
+ {
+ DPRINT("Setting up Bcb #%x\n", i);
+
+ Bcb = &CcCacheSections[i];
+
+ ASSERT(Bcb->RefCount < 2);
+
+ if (Bcb->RefCount > 0)
+ {
+ CcpDereferenceCache(i, FALSE);
+ }
+
+ ASSERT(!Bcb->RefCount);
+ Bcb->RefCount = 1;
+
+ DPRINT("Bcb #%x RefCount %d\n", Bcb - CcCacheSections, Bcb->RefCount);
+
+ if (!RtlTestBit(CcCacheBitmap, i))
+ {
+ DPRINT("Somebody stoeled BCB #%x\n", i);
+ }
+ ASSERT(RtlTestBit(CcCacheBitmap, i));
+
+ DPRINT("Allocated #%x\n", i);
+ ASSERT(CcCacheSections[i].RefCount);
+ }
+ else
+ {
+ DPRINT("Failed to allocate cache segment\n");
+ }
+ return i;
+}
+
+/* Must have acquired the mutex */
+VOID CcpReferenceCache(ULONG Start)
+{
+ PNOCC_BCB Bcb;
+ Bcb = &CcCacheSections[Start];
+ ASSERT(Bcb->SectionObject);
+ Bcb->RefCount++;
+ RtlSetBit(CcCacheBitmap, Start);
+
+}
+
+VOID CcpMarkForExclusive(ULONG Start)
+{
+ PNOCC_BCB Bcb;
+ Bcb = &CcCacheSections[Start];
+ Bcb->ExclusiveWaiter++;
+}
+
+/* Must not have the mutex */
+VOID CcpReferenceCacheExclusive(ULONG Start)
+{
+ PNOCC_BCB Bcb = &CcCacheSections[Start];
+
+ KeWaitForSingleObject(&Bcb->ExclusiveWait, Executive, KernelMode, FALSE, NULL);
+ CcpLock();
+ ASSERT(Bcb->ExclusiveWaiter);
+ ASSERT(Bcb->SectionObject);
+ Bcb->Exclusive = TRUE;
+ Bcb->ExclusiveWaiter--;
+ RtlSetBit(CcCacheBitmap, Start);
+ CcpUnlock();
+}
+
+/* Find a map that encompasses the target range */
+/* Must have the mutex */
+ULONG CcpFindMatchingMap(PLIST_ENTRY Head, PLARGE_INTEGER FileOffset, ULONG Length)
+{
+ PLIST_ENTRY Entry;
+ //DPRINT("Find Matching Map: (%x) %x:%x\n", FileOffset->LowPart, Length);
+ for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
+ {
+ //DPRINT("Link @%x\n", Entry);
+ PNOCC_BCB Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
+ //DPRINT("Selected BCB %x #%x\n", Bcb, Bcb - CcCacheSections);
+ //DPRINT("This File: %x:%x\n", Bcb->FileOffset.LowPart, Bcb->Length);
+ if (FileOffset->QuadPart >= Bcb->FileOffset.QuadPart &&
+ FileOffset->QuadPart < Bcb->FileOffset.QuadPart + CACHE_STRIPE)
+ {
+ //DPRINT("Found match at #%x\n", Bcb - CcCacheSections);
+ return Bcb - CcCacheSections;
+ }
+ }
+
+ //DPRINT("This region isn't mapped\n");
+
+ return INVALID_CACHE;
+}
+
+BOOLEAN
+NTAPI
+CcpMapData
+(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ OUT PVOID *BcbResult,
+ OUT PVOID *Buffer)
+{
+ BOOLEAN Success = FALSE, FaultIn = FALSE;
+ /* Note: windows 2000 drivers treat this as a bool */
+ //BOOLEAN Wait = (Flags & MAP_WAIT) || (Flags == TRUE);
+ LARGE_INTEGER Target, EndInterval;
+ ULONG BcbHead;
+ PNOCC_BCB Bcb = NULL;
+ PMM_CACHE_SECTION_SEGMENT SectionObject = NULL;
+ NTSTATUS Status;
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+
+ if (!Map)
+ {
+ DPRINT1("File object was not mapped\n");
+ return FALSE;
+ }
+
+ DPRINT("CcMapData(F->%x,%08x%08x:%d)\n", FileObject, FileOffset->HighPart, FileOffset->LowPart, Length);
+
+ ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ Target.HighPart = FileOffset->HighPart;
+ Target.LowPart = CACHE_ROUND_DOWN(FileOffset->LowPart);
+
+ CcpLock();
+
+ /* Find out if any range is a superset of what we want */
+ /* Find an accomodating section */
+ BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
+
+ if (BcbHead != INVALID_CACHE)
+ {
+ Bcb = &CcCacheSections[BcbHead];
+ Success = TRUE;
+ *BcbResult = Bcb;
+ *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
+ DPRINT
+ ("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
+ Bcb - CcCacheSections,
+ Bcb->FileOffset.HighPart,
+ Bcb->FileOffset.LowPart,
+ Bcb->BaseAddress,
+ Bcb->Length,
+ *Buffer,
+ Length,
+ &FileObject->FileName);
+ DPRINT("w1n\n");
+ goto cleanup;
+ }
+
+ ULONG SectionSize;
+
+ DPRINT("File size %08x%08x\n", Map->FileSizes.ValidDataLength.HighPart, Map->FileSizes.ValidDataLength.LowPart);
+
+ if (Map->FileSizes.ValidDataLength.QuadPart)
+ {
+ SectionSize = min(CACHE_STRIPE, Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart);
+ }
+ else
+ {
+ SectionSize = CACHE_STRIPE;
+ }
+
+ DPRINT("Allocating a cache stripe at %x:%d\n",
+ Target.LowPart, SectionSize);
+ //ASSERT(SectionSize <= CACHE_STRIPE);
+
+ CcpUnlock();
+ Status = CcpAllocateSection
+ (FileObject,
+ SectionSize,
+#ifdef PIN_WRITE_ONLY
+ PAGE_READONLY,
+#else
+ PAGE_READWRITE,
+#endif
+ &SectionObject);
+ CcpLock();
+
+ if (!NT_SUCCESS(Status))
+ {
+ *BcbResult = NULL;
+ *Buffer = NULL;
+ DPRINT1("End %08x\n", Status);
+ goto cleanup;
+ }
+
+retry:
+ /* Returns a reference */
+ DPRINT("Allocating cache sections: %wZ\n", &FileObject->FileName);
+ BcbHead = CcpAllocateCacheSections(FileObject, SectionObject);
+ if (BcbHead == INVALID_CACHE)
+ {
+ ULONG i;
+ DbgPrint("Cache Map:");
+ for (i = 0; i < CACHE_NUM_SECTIONS; i++)
+ {
+ if (!(i % 64)) DbgPrint("\n");
+ DbgPrint("%c", CcCacheSections[i].RefCount + (RtlTestBit(CcCacheBitmap, i) ? '@' : '`'));
+ }
+ DbgPrint("\n");
+ KeWaitForSingleObject(&CcDeleteEvent, Executive, KernelMode, FALSE, NULL);
+ goto retry;
+ }
+
+ DPRINT("BcbHead #%x (final)\n", BcbHead);
+
+ if (BcbHead == INVALID_CACHE)
+ {
+ *BcbResult = NULL;
+ *Buffer = NULL;
+ DPRINT1("End\n");
+ goto cleanup;
+ }
+
+ DPRINT("Selected BCB #%x\n", BcbHead);
+ ULONG ViewSize = CACHE_STRIPE;
+
+ Bcb = &CcCacheSections[BcbHead];
+ Status = MmMapCacheViewInSystemSpaceAtOffset
+ (SectionObject,
+ &Bcb->BaseAddress,
+ &Target,
+ &ViewSize);
+
+ if (!NT_SUCCESS(Status))
+ {
+ *BcbResult = NULL;
+ *Buffer = NULL;
+ MmFinalizeSegment(SectionObject);
+ RemoveEntryList(&Bcb->ThisFileList);
+ RtlZeroMemory(Bcb, sizeof(*Bcb));
+ RtlClearBit(CcCacheBitmap, BcbHead);
+ DPRINT1("Failed to map\n");
+ goto cleanup;
+ }
+
+ Success = TRUE;
+ //DPRINT("w1n\n");
+
+ Bcb->Length = MIN(Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart, CACHE_STRIPE);
+ Bcb->SectionObject = SectionObject;
+ Bcb->Map = Map;
+ Bcb->FileOffset = Target;
+ InsertTailList(&Map->AssociatedBcb, &Bcb->ThisFileList);
+
+ *BcbResult = &CcCacheSections[BcbHead];
+ *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
+ FaultIn = TRUE;
+
+ DPRINT
+ ("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
+ Bcb - CcCacheSections,
+ Bcb->FileOffset.HighPart,
+ Bcb->FileOffset.LowPart,
+ Bcb->BaseAddress,
+ Bcb->Length,
+ *Buffer,
+ Length,
+ &FileObject->FileName);
+
+ EndInterval.QuadPart = Bcb->FileOffset.QuadPart + Bcb->Length - 1;
+ ASSERT((EndInterval.QuadPart & ~(CACHE_STRIPE - 1)) == (Bcb->FileOffset.QuadPart & ~(CACHE_STRIPE - 1)));
+
+ //DPRINT("TERM!\n");
+
+cleanup:
+ CcpUnlock();
+ if (Success)
+ {
+ if (FaultIn)
+ {
+ // Fault in the pages. This forces reads to happen now.
+ ULONG i;
+ CHAR Dummy;
+ PCHAR FaultIn = Bcb->BaseAddress;
+ DPRINT1
+ ("Faulting in pages at this point: file %wZ %08x%08x:%x\n",
+ &FileObject->FileName,
+ Bcb->FileOffset.HighPart,
+ Bcb->FileOffset.LowPart,
+ Bcb->Length);
+ for (i = 0; i < Bcb->Length; i++)
+ {
+ Dummy = FaultIn[i];
+ }
+ }
+ ASSERT(Bcb >= CcCacheSections && Bcb < (CcCacheSections + CACHE_NUM_SECTIONS));
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
+
+ return Success;
+}
+
+BOOLEAN
+NTAPI
+CcMapData
+(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ OUT PVOID *BcbResult,
+ OUT PVOID *Buffer)
+{
+ BOOLEAN Result;
+
+ Result = CcpMapData
+ (FileObject,
+ FileOffset,
+ Length,
+ Flags,
+ BcbResult,
+ Buffer);
+
+ if (Result)
+ {
+ PNOCC_BCB Bcb = (PNOCC_BCB)*BcbResult;
+ ASSERT(Bcb >= CcCacheSections && Bcb < CcCacheSections + CACHE_NUM_SECTIONS);
+ ASSERT(Bcb->BaseAddress);
+ CcpLock();
+ CcpReferenceCache(Bcb - CcCacheSections);
+ CcpUnlock();
+ }
+
+ return Result;
+}
+
+BOOLEAN
+NTAPI
+CcpPinMappedData(IN PNOCC_CACHE_MAP Map,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ IN OUT PVOID *Bcb)
+{
+ BOOLEAN Exclusive = Flags & PIN_EXCLUSIVE;
+ ULONG BcbHead;
+ PNOCC_BCB TheBcb;
+
+ CcpLock();
+
+ ASSERT(Map->AssociatedBcb.Flink == &Map->AssociatedBcb || (CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) >= CcCacheSections && CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) < CcCacheSections + CACHE_NUM_SECTIONS));
+ BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
+ if (BcbHead == INVALID_CACHE)
+ {
+ CcpUnlock();
+ return FALSE;
+ }
+
+ TheBcb = &CcCacheSections[BcbHead];
+
+ if (Exclusive)
+ {
+ DPRINT("Requesting #%x Exclusive\n", BcbHead);
+ CcpMarkForExclusive(BcbHead);
+ }
+ else
+ {
+ DPRINT("Reference #%x\n", BcbHead);
+ CcpReferenceCache(BcbHead);
+ }
+
+ if (Exclusive)
+ CcpReferenceCacheExclusive(BcbHead);
+
+ CcpUnlock();
+
+ *Bcb = TheBcb;
+ return TRUE;
+}
+
+BOOLEAN
+NTAPI
+CcPinMappedData(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ IN OUT PVOID *Bcb)
+{
+ PVOID Buffer;
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+
+ if (!Map)
+ {
+ DPRINT1("Not cached\n");
+ return FALSE;
+ }
+
+ if (CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, &Buffer))
+ {
+ return CcpPinMappedData(Map, FileOffset, Length, Flags, Bcb);
+ }
+ else
+ {
+ DPRINT1("could not map\n");
+ return FALSE;
+ }
+}
+
+BOOLEAN
+NTAPI
+CcPinRead(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ OUT PVOID *Bcb,
+ OUT PVOID *Buffer)
+{
+ PNOCC_BCB RealBcb;
+ BOOLEAN Result;
+
+ Result = CcPinMappedData
+ (FileObject,
+ FileOffset,
+ Length,
+ Flags,
+ Bcb);
+
+ if (Result)
+ {
+ CcpLock();
+ RealBcb = *Bcb;
+ *Buffer = ((PCHAR)RealBcb->BaseAddress) + (int)(FileOffset->QuadPart - RealBcb->FileOffset.QuadPart);
+ CcpUnlock();
+ }
+
+ return Result;
+}
+
+BOOLEAN
+NTAPI
+CcPreparePinWrite(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN BOOLEAN Zero,
+ IN ULONG Flags,
+ OUT PVOID *Bcb,
+ OUT PVOID *Buffer)
+{
+ BOOLEAN Result;
+ PNOCC_BCB RealBcb;
+#ifdef PIN_WRITE_ONLY
+ PVOID BaseAddress;
+ SIZE_T NumberOfBytes;
+ ULONG OldProtect;
+#endif
+
+ DPRINT1("CcPreparePinWrite(%x:%x)\n", Buffer, Length);
+
+ Result = CcPinRead
+ (FileObject,
+ FileOffset,
+ Length,
+ Flags,
+ Bcb,
+ Buffer);
+
+ if (Result)
+ {
+ CcpLock();
+ RealBcb = *Bcb;
+
+#ifdef PIN_WRITE_ONLY
+ BaseAddress = RealBcb->BaseAddress;
+ NumberOfBytes = RealBcb->Length;
+
+ MiProtectVirtualMemory
+ (NULL,
+ &BaseAddress,
+ &NumberOfBytes,
+ PAGE_READWRITE,
+ &OldProtect);
+#endif
+
+ CcpUnlock();
+ RealBcb->Dirty = TRUE;
+
+ if (Zero)
+ {
+ DPRINT
+ ("Zero fill #%x %08x%08x:%x Buffer %x %wZ\n",
+ RealBcb - CcCacheSections,
+ FileOffset->u.HighPart,
+ FileOffset->u.LowPart,
+ Length,
+ *Buffer,
+ &FileObject->FileName);
+
+ DPRINT1("RtlZeroMemory(%x,%x)\n", *Buffer, Length);
+ RtlZeroMemory(*Buffer, Length);
+ }
+ }
+
+ return Result;
+}
+
+VOID
+NTAPI
+CcpUnpinData(IN PNOCC_BCB RealBcb)
+{
+ if (RealBcb->RefCount <= 2)
+ {
+ RealBcb->Exclusive = FALSE;
+ if (RealBcb->ExclusiveWaiter)
+ {
+ DPRINT("Triggering exclusive waiter\n");
+ KeSetEvent(&RealBcb->ExclusiveWait, IO_NO_INCREMENT, FALSE);
+ return;
+ }
+ }
+ if (RealBcb->RefCount > 1)
+ {
+ DPRINT("Removing one reference #%x\n", RealBcb - CcCacheSections);
+ RealBcb->RefCount--;
+ KeSetEvent(&CcDeleteEvent, IO_DISK_INCREMENT, FALSE);
+ }
+ if (RealBcb->RefCount == 1)
+ {
+ DPRINT("Clearing allocation bit #%x\n", RealBcb - CcCacheSections);
+ RtlClearBit(CcCacheBitmap, RealBcb - CcCacheSections);
+
+#ifdef PIN_WRITE_ONLY
+ PVOID BaseAddress = RealBcb->BaseAddress;
+ SIZE_T NumberOfBytes = RealBcb->Length;
+ ULONG OldProtect;
+
+ MiProtectVirtualMemory
+ (NULL,
+ &BaseAddress,
+ &NumberOfBytes,
+ PAGE_READONLY,
+ &OldProtect);
+#endif
+ }
+}
+
+VOID
+NTAPI
+CcUnpinData(IN PVOID Bcb)
+{
+ PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
+ ULONG Selected = RealBcb - CcCacheSections;
+
+ ASSERT(RealBcb >= CcCacheSections && RealBcb - CcCacheSections < CACHE_NUM_SECTIONS);
+ DPRINT("CcUnpinData Bcb #%x (RefCount %d)\n", Selected, RealBcb->RefCount);
+
+ CcpLock();
+ CcpUnpinData(RealBcb);
+ CcpUnlock();
+}
+
+VOID
+NTAPI
+CcSetBcbOwnerPointer(IN PVOID Bcb,
+ IN PVOID OwnerPointer)
+{
+ PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
+ CcpLock();
+ CcpReferenceCache(RealBcb - CcCacheSections);
+ RealBcb->OwnerPointer = OwnerPointer;
+ CcpUnlock();
+}
+
+VOID
+NTAPI
+CcUnpinDataForThread(IN PVOID Bcb,
+ IN ERESOURCE_THREAD ResourceThreadId)
+{
+ CcUnpinData(Bcb);
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/section/data.c b/reactos/ntoskrnl/cache/section/data.c
new file mode 100644
index 00000000000..89cdf74c5de
--- /dev/null
+++ b/reactos/ntoskrnl/cache/section/data.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/section.c
+ * PURPOSE: Implements section objects
+ *
+ * PROGRAMMERS: Rex Jolliff
+ * David Welch
+ * Eric Kohl
+ * Emanuele Aliberti
+ * Eugene Ingerman
+ * Casper Hornstrup
+ * KJK::Hyperion
+ * Guido de Jong
+ * Ge van Geldorp
+ * Royce Mitchell III
+ * Filip Navara
+ * Aleksey Bragin
+ * Jason Filby
+ * Thomas Weidenmueller
+ * Gunnar Andre' Dalsnes
+ * Mike Nordell
+ * Alex Ionescu
+ * Gregor Anich
+ * Steven Edwards
+ * Herve Poussineau
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include
+#include "newmm.h"
+#include "../newcc.h"
+#define NDEBUG
+#include
+
+#define DPRINTC DPRINT
+
+extern KEVENT MpwThreadEvent;
+extern KSPIN_LOCK MiSectionPageTableLock;
+
+/* GLOBALS *******************************************************************/
+
+ULONG_PTR MmSubsectionBase;
+BOOLEAN MmAllocationFragment;
+
+NTSTATUS
+NTAPI
+MiSimpleRead
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ PVOID Buffer,
+ ULONG Length,
+ PIO_STATUS_BLOCK ReadStatus);
+
+static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
+{
+ ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
+ ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
+};
+
+/* FUNCTIONS *****************************************************************/
+
+/* Note: Mmsp prefix denotes "Memory Manager Section Private". */
+
+VOID
+NTAPI
+_MmLockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line)
+{
+ DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line);
+ ExAcquireFastMutex(&Segment->Lock);
+}
+
+VOID
+NTAPI
+_MmUnlockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line)
+{
+ ExReleaseFastMutex(&Segment->Lock);
+ DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
+}
+
+NTSTATUS
+NTAPI
+MiZeroFillSection
+(PVOID Address,
+ PLARGE_INTEGER FileOffsetPtr,
+ ULONG Length)
+{
+ PFN_NUMBER Page;
+ PMMSUPPORT AddressSpace;
+ PMEMORY_AREA MemoryArea;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ LARGE_INTEGER FileOffset = *FileOffsetPtr, End, FirstMapped;
+ DPRINT1("MiZeroFillSection(Address %x,Offset %x,Length %x)\n", Address, FileOffset.LowPart, Length);
+ AddressSpace = MmGetKernelAddressSpace();
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
+ MmUnlockAddressSpace(AddressSpace);
+ if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
+ {
+ return STATUS_NOT_MAPPED_DATA;
+ }
+
+ Segment = MemoryArea->Data.CacheData.Segment;
+ End.QuadPart = FileOffset.QuadPart + Length;
+ End.LowPart = PAGE_ROUND_DOWN(End.LowPart);
+ FileOffset.LowPart = PAGE_ROUND_UP(FileOffset.LowPart);
+ FirstMapped.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart;
+ DPRINT
+ ("Pulling zero pages for %08x%08x-%08x%08x\n",
+ FileOffset.u.HighPart, FileOffset.u.LowPart,
+ End.u.HighPart, End.u.LowPart);
+ while (FileOffset.QuadPart < End.QuadPart)
+ {
+ PVOID Address;
+ ULONG Entry;
+
+ if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page)))
+ break;
+
+ MmLockAddressSpace(AddressSpace);
+ MmLockCacheSectionSegment(Segment);
+
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, &FileOffset);
+ if (Entry == 0)
+ {
+ MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, MAKE_PFN_SSE(Page));
+ Address = ((PCHAR)MemoryArea->StartingAddress) + FileOffset.QuadPart - FirstMapped.QuadPart;
+ MmReferencePage(Page);
+ MmCreateVirtualMapping(NULL, Address, PAGE_READWRITE, &Page, 1);
+ MmInsertRmap(Page, NULL, Address);
+ }
+ else
+ MmReleasePageMemoryConsumer(MC_CACHE, Page);
+
+ MmUnlockCacheSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+
+ FileOffset.QuadPart += PAGE_SIZE;
+ }
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+_MiFlushMappedSection
+(PVOID BaseAddress,
+ PLARGE_INTEGER BaseOffset,
+ PLARGE_INTEGER FileSize,
+ BOOLEAN WriteData,
+ const char *File,
+ int Line)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG_PTR PageAddress;
+ PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
+ PMEMORY_AREA MemoryArea;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ ULONG_PTR BeginningAddress, EndingAddress;
+ LARGE_INTEGER ViewOffset;
+ LARGE_INTEGER FileOffset;
+ PFN_NUMBER Page;
+ PPFN_NUMBER Pages;
+
+ DPRINT1("MiFlushMappedSection(%x,%08x,%x,%d,%s:%d)\n", BaseAddress, BaseOffset->LowPart, FileSize, WriteData, File, Line);
+
+ MmLockAddressSpace(AddressSpace);
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
+ if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ return STATUS_NOT_MAPPED_DATA;
+ }
+ BeginningAddress = PAGE_ROUND_DOWN((ULONG_PTR)MemoryArea->StartingAddress);
+ EndingAddress = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress);
+ Segment = MemoryArea->Data.CacheData.Segment;
+ ViewOffset.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart;
+
+ ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart);
+
+ MmLockCacheSectionSegment(Segment);
+
+ Pages = ExAllocatePool
+ (NonPagedPool,
+ sizeof(PFN_NUMBER) *
+ ((EndingAddress - BeginningAddress) >> PAGE_SHIFT));
+
+ if (!Pages)
+ {
+ ASSERT(FALSE);
+ }
+
+ for (PageAddress = BeginningAddress;
+ PageAddress < EndingAddress;
+ PageAddress += PAGE_SIZE)
+ {
+ ULONG Entry;
+ FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
+ Entry =
+ MiGetPageEntryCacheSectionSegment
+ (MemoryArea->Data.CacheData.Segment,
+ &FileOffset);
+ Page = PFN_FROM_SSE(Entry);
+ if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) &&
+ (MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) &&
+ FileOffset.QuadPart < FileSize->QuadPart)
+ {
+ Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Page;
+ }
+ else
+ Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0;
+ }
+
+ MmUnlockCacheSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+
+ for (PageAddress = BeginningAddress;
+ PageAddress < EndingAddress;
+ PageAddress += PAGE_SIZE)
+ {
+ FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
+ Page = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
+ if (Page)
+ {
+ ULONG Entry;
+ if (WriteData) {
+ DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart);
+ Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page);
+ } else
+ Status = STATUS_SUCCESS;
+
+ if (NT_SUCCESS(Status)) {
+ MmLockAddressSpace(AddressSpace);
+ MmSetCleanAllRmaps(Page);
+ MmLockCacheSectionSegment(Segment);
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, &FileOffset);
+ if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page)
+ MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry));
+ MmUnlockCacheSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+ } else {
+ DPRINT
+ ("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n",
+ FileOffset.u.HighPart, FileOffset.u.LowPart,
+ (ULONG)(FileSize->QuadPart - FileOffset.QuadPart),
+ PageAddress,
+ Page,
+ FileSize->u.HighPart,
+ FileSize->u.LowPart,
+ &Segment->FileObject->FileName,
+ Status);
+ }
+ }
+ }
+
+ ExFreePool(Pages);
+
+ return Status;
+}
+
+VOID
+NTAPI
+MmFinalizeSegment(PMM_CACHE_SECTION_SEGMENT Segment)
+{
+ KIRQL OldIrql = 0;
+
+ MmLockCacheSectionSegment(Segment);
+ if (Segment->Flags & MM_DATAFILE_SEGMENT) {
+ KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql);
+ if (Segment->Flags & MM_SEGMENT_FINALIZE) {
+ KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
+ MmUnlockCacheSectionSegment(Segment);
+ return;
+ } else {
+ Segment->Flags |= MM_SEGMENT_FINALIZE;
+ }
+ }
+ DPRINTC("Finalizing segment %x\n", Segment);
+ if (Segment->Flags & MM_DATAFILE_SEGMENT)
+ {
+ //Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
+ KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
+ MiFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
+ MmUnlockCacheSectionSegment(Segment);
+ ObDereferenceObject(Segment->FileObject);
+ } else {
+ MiFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
+ MmUnlockCacheSectionSegment(Segment);
+ }
+ DPRINTC("Segment %x destroy\n", Segment);
+ ExFreePool(Segment);
+}
+
+NTSTATUS
+NTAPI
+MmCreateCacheSection
+(PMM_CACHE_SECTION_SEGMENT *SegmentObject,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ PLARGE_INTEGER UMaximumSize,
+ ULONG SectionPageProtection,
+ ULONG AllocationAttributes,
+ PFILE_OBJECT FileObject)
+/*
+ * Create a section backed by a data file
+ */
+{
+ NTSTATUS Status;
+ ULARGE_INTEGER MaximumSize;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ ULONG FileAccess;
+ IO_STATUS_BLOCK Iosb;
+ CC_FILE_SIZES FileSizes;
+ FILE_STANDARD_INFORMATION FileInfo;
+
+ /*
+ * Check file access required
+ */
+ if (SectionPageProtection & PAGE_READWRITE ||
+ SectionPageProtection & PAGE_EXECUTE_READWRITE)
+ {
+ FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
+ }
+ else
+ {
+ FileAccess = FILE_READ_DATA;
+ }
+
+ /*
+ * Reference the file handle
+ */
+ ObReferenceObject(FileObject);
+
+ DPRINT("Getting original file size\n");
+ /* A hack: If we're cached, we can overcome deadlocking with the upper
+ * layer filesystem call by retriving the object sizes from the cache
+ * which is made to keep track. If I had to guess, they were figuring
+ * out a similar problem.
+ */
+ if (!CcGetFileSizes(FileObject, &FileSizes))
+ {
+ /*
+ * FIXME: This is propably not entirely correct. We can't look into
+ * the standard FCB header because it might not be initialized yet
+ * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
+ * standard file information is filled on first request).
+ */
+ Status = IoQueryFileInformation
+ (FileObject,
+ FileStandardInformation,
+ sizeof(FILE_STANDARD_INFORMATION),
+ &FileInfo,
+ &Iosb.Information);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ ASSERT(Status != STATUS_PENDING);
+
+ FileSizes.ValidDataLength = FileInfo.EndOfFile;
+ FileSizes.FileSize = FileInfo.EndOfFile;
+ }
+ DPRINT("Got %08x\n", FileSizes.ValidDataLength.u.LowPart);
+
+ /*
+ * FIXME: Revise this once a locking order for file size changes is
+ * decided
+ */
+ if (UMaximumSize != NULL)
+ {
+ MaximumSize.QuadPart = UMaximumSize->QuadPart;
+ }
+ else
+ {
+ DPRINT("Got file size %08x%08x\n", FileSizes.FileSize.u.HighPart, FileSizes.FileSize.u.LowPart);
+ MaximumSize.QuadPart = FileSizes.FileSize.QuadPart;
+ }
+
+ Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_CACHE_SECTION_SEGMENT),
+ TAG_MM_SECTION_SEGMENT);
+ if (Segment == NULL)
+ {
+ return(STATUS_NO_MEMORY);
+ }
+
+ ExInitializeFastMutex(&Segment->Lock);
+
+ Segment->ReferenceCount = 1;
+
+ /*
+ * Set the lock before assigning the segment to the file object
+ */
+ ExAcquireFastMutex(&Segment->Lock);
+
+ DPRINT("Filling out Segment info (No previous data section)\n");
+ ObReferenceObject(FileObject);
+ Segment->FileObject = FileObject;
+ Segment->Protection = SectionPageProtection;
+ Segment->Flags = MM_DATAFILE_SEGMENT;
+ memset(&Segment->Image, 0, sizeof(Segment->Image));
+ Segment->WriteCopy = FALSE;
+ if (AllocationAttributes & SEC_RESERVE)
+ {
+ Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
+ }
+ else
+ {
+ Segment->RawLength = MaximumSize;
+ Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
+ }
+
+ MiInitializeSectionPageTable(Segment);
+ MmUnlockCacheSectionSegment(Segment);
+
+ /* Extend file if section is longer */
+ DPRINT("MaximumSize %08x%08x ValidDataLength %08x%08x\n",
+ MaximumSize.u.HighPart, MaximumSize.u.LowPart,
+ FileSizes.ValidDataLength.u.HighPart, FileSizes.ValidDataLength.u.LowPart);
+ if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart)
+ {
+ DPRINT("Changing file size to %08x%08x, segment %x\n", MaximumSize.u.HighPart, MaximumSize.u.LowPart, Segment);
+ Status = IoSetInformation(FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), &MaximumSize);
+ DPRINT("Change: Status %x\n", Status);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Could not expand section\n");
+ return Status;
+ }
+ }
+
+ DPRINTC("Segment %x created (%x)\n", Segment, Segment->Flags);
+
+ *SegmentObject = Segment;
+
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+NTAPI
+_MiMapViewOfSegment
+(PMMSUPPORT AddressSpace,
+ PMM_CACHE_SECTION_SEGMENT Segment,
+ PVOID* BaseAddress,
+ SIZE_T ViewSize,
+ ULONG Protect,
+ PLARGE_INTEGER ViewOffset,
+ ULONG AllocationType,
+ const char *file,
+ int line)
+{
+ PMEMORY_AREA MArea;
+ NTSTATUS Status;
+ PHYSICAL_ADDRESS BoundaryAddressMultiple;
+
+ BoundaryAddressMultiple.QuadPart = 0;
+
+ Status = MmCreateMemoryArea
+ (AddressSpace,
+ MEMORY_AREA_CACHE,
+ BaseAddress,
+ ViewSize,
+ Protect,
+ &MArea,
+ FALSE,
+ AllocationType,
+ BoundaryAddressMultiple);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
+ (*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
+ return(Status);
+ }
+
+ DPRINTC("MiMapViewOfSegment %x %x %x %x %x %wZ %s:%d\n", MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, Segment, ViewOffset ? ViewOffset->LowPart : 0, ViewSize, Segment->FileObject ? &Segment->FileObject->FileName : NULL, file, line);
+
+ MArea->Data.CacheData.Segment = Segment;
+ if (ViewOffset)
+ MArea->Data.CacheData.ViewOffset = *ViewOffset;
+ else
+ MArea->Data.CacheData.ViewOffset.QuadPart = 0;
+
+#if 0
+ MArea->NotPresent = MmNotPresentFaultPageFile;
+ MArea->AccessFault = MiCowSectionPage;
+ MArea->PageOut = MmPageOutPageFileView;
+#endif
+
+ DPRINTC
+ ("MiMapViewOfSegment(P %x, A %x, T %x)\n",
+ MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, MArea->Type);
+
+ return(STATUS_SUCCESS);
+}
+
+VOID
+NTAPI
+MiFreeSegmentPage
+(PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER FileOffset)
+{
+ ULONG Entry;
+ PFILE_OBJECT FileObject = Segment->FileObject;
+
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, FileOffset);
+ DPRINTC("MiFreeSegmentPage(%x:%08x%08x -> Entry %x\n",
+ Segment, FileOffset->HighPart, FileOffset->LowPart, Entry);
+
+ if (Entry && !IS_SWAP_FROM_SSE(Entry))
+ {
+ // The segment is carrying a dirty page.
+ PFN_NUMBER OldPage = PFN_FROM_SSE(Entry);
+ if (IS_DIRTY_SSE(Entry) && FileObject)
+ {
+ DPRINT("MiWriteBackPage(%x,%wZ,%08x%08x)\n", Segment, &FileObject->FileName, FileOffset->u.HighPart, FileOffset->u.LowPart);
+ MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage);
+ }
+ DPRINTC("Free page %x (off %x from %x) (ref ct %d, ent %x, dirty? %s)\n", OldPage, FileOffset->LowPart, Segment, MmGetReferenceCountPage(OldPage), Entry, IS_DIRTY_SSE(Entry) ? "true" : "false");
+
+ MiSetPageEntryCacheSectionSegment(Segment, FileOffset, 0);
+ MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
+ }
+ else if (IS_SWAP_FROM_SSE(Entry))
+ {
+ DPRINT("Free swap\n");
+ MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
+ }
+
+ DPRINT("Done\n");
+}
+
+VOID
+MmFreeCacheSectionPage
+(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
+ PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
+{
+ ULONG Entry;
+ PVOID *ContextData = Context;
+ PMMSUPPORT AddressSpace;
+ PEPROCESS Process;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ LARGE_INTEGER Offset;
+
+ DPRINT("MmFreeSectionPage(%x,%x,%x,%x,%d)\n", MmGetAddressSpaceOwner(ContextData[0]), Address, Page, SwapEntry, Dirty);
+
+ AddressSpace = ContextData[0];
+ Process = MmGetAddressSpaceOwner(AddressSpace);
+ Address = (PVOID)PAGE_ROUND_DOWN(Address);
+ Segment = ContextData[1];
+ Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress +
+ MemoryArea->Data.CacheData.ViewOffset.QuadPart;
+
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, &Offset);
+
+ if (Page)
+ {
+ DPRINT("Removing page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
+ MmSetSavedSwapEntryPage(Page, 0);
+ MmDeleteRmap(Page, Process, Address);
+ MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
+ MmReleasePageMemoryConsumer(MC_CACHE, Page);
+ }
+ if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty)
+ {
+ DPRINT("Freeing section page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
+ MiSetPageEntryCacheSectionSegment(Segment, &Offset, DIRTY_SSE(Entry));
+ }
+ else if (SwapEntry != 0)
+ {
+ MmFreeSwapPage(SwapEntry);
+ }
+}
+
+NTSTATUS
+NTAPI
+MmUnmapViewOfCacheSegment
+(PMMSUPPORT AddressSpace,
+ PVOID BaseAddress)
+{
+ PVOID Context[2];
+ PMEMORY_AREA MemoryArea;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
+ if (MemoryArea == NULL)
+ {
+ ASSERT(MemoryArea);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ MemoryArea->DeleteInProgress = TRUE;
+ Segment = MemoryArea->Data.CacheData.Segment;
+ MemoryArea->Data.CacheData.Segment = NULL;
+
+ MmLockCacheSectionSegment(Segment);
+
+ Context[0] = AddressSpace;
+ Context[1] = Segment;
+ DPRINT("MmFreeMemoryArea(%x,%x)\n", MmGetAddressSpaceOwner(AddressSpace), MemoryArea->StartingAddress);
+ MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context);
+
+ MmUnlockCacheSectionSegment(Segment);
+
+ DPRINTC("MiUnmapViewOfSegment %x %x %x\n", MmGetAddressSpaceOwner(AddressSpace), BaseAddress, Segment);
+
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+NTAPI
+MmExtendCacheSection
+(PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER NewSize,
+ BOOLEAN ExtendFile)
+{
+ LARGE_INTEGER OldSize;
+ DPRINT("Extend Segment %x\n", Segment);
+
+ MmLockCacheSectionSegment(Segment);
+ OldSize.QuadPart = Segment->RawLength.QuadPart;
+ MmUnlockCacheSectionSegment(Segment);
+
+ DPRINT("OldSize %08x%08x NewSize %08x%08x\n",
+ OldSize.u.HighPart, OldSize.u.LowPart,
+ NewSize->u.HighPart, NewSize->u.LowPart);
+
+ if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart)
+ {
+ NTSTATUS Status;
+ Status = IoSetInformation(Segment->FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), NewSize);
+ if (!NT_SUCCESS(Status)) return Status;
+ }
+
+ MmLockCacheSectionSegment(Segment);
+ Segment->RawLength.QuadPart = NewSize->QuadPart;
+ Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, PAGE_ROUND_UP(Segment->RawLength.LowPart));
+ MmUnlockCacheSectionSegment(Segment);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MmMapCacheViewInSystemSpaceAtOffset
+(IN PMM_CACHE_SECTION_SEGMENT Segment,
+ OUT PVOID *MappedBase,
+ PLARGE_INTEGER FileOffset,
+ IN OUT PULONG ViewSize)
+{
+ PMMSUPPORT AddressSpace;
+ NTSTATUS Status;
+
+ DPRINT("MmMapViewInSystemSpaceAtOffset() called offset %08x%08x\n", FileOffset->HighPart, FileOffset->LowPart);
+
+ AddressSpace = MmGetKernelAddressSpace();
+
+ MmLockAddressSpace(AddressSpace);
+ MmLockCacheSectionSegment(Segment);
+
+ Status = MiMapViewOfSegment
+ (AddressSpace,
+ Segment,
+ MappedBase,
+ *ViewSize,
+ PAGE_READWRITE,
+ FileOffset,
+ 0);
+
+ MmUnlockCacheSectionSegment(Segment);
+ MmUnlockAddressSpace(AddressSpace);
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase)
+{
+ PMMSUPPORT AddressSpace;
+ NTSTATUS Status;
+
+ DPRINT("MmUnmapViewInSystemSpace() called\n");
+
+ AddressSpace = MmGetKernelAddressSpace();
+
+ Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase);
+
+ return Status;
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/cache/section/fault.c b/reactos/ntoskrnl/cache/section/fault.c
new file mode 100644
index 00000000000..81d6a0171e2
--- /dev/null
+++ b/reactos/ntoskrnl/cache/section/fault.c
@@ -0,0 +1,728 @@
+/*
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/section/fault.c
+ * PURPOSE: Consolidate fault handlers for sections
+ *
+ * PROGRAMMERS: Arty
+ * Rex Jolliff
+ * David Welch
+ * Eric Kohl
+ * Emanuele Aliberti
+ * Eugene Ingerman
+ * Casper Hornstrup
+ * KJK::Hyperion
+ * Guido de Jong
+ * Ge van Geldorp
+ * Royce Mitchell III
+ * Filip Navara
+ * Aleksey Bragin
+ * Jason Filby
+ * Thomas Weidenmueller
+ * Gunnar Andre' Dalsnes
+ * Mike Nordell
+ * Alex Ionescu
+ * Gregor Anich
+ * Steven Edwards
+ * Herve Poussineau
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include
+#include "newmm.h"
+#define NDEBUG
+#include
+
+#define DPRINTC DPRINT
+
+extern KEVENT MmWaitPageEvent;
+
+NTSTATUS
+NTAPI
+MmNotPresentFaultCachePage
+(PMMSUPPORT AddressSpace,
+ MEMORY_AREA* MemoryArea,
+ PVOID Address,
+ BOOLEAN Locked,
+ PMM_REQUIRED_RESOURCES Required)
+{
+ NTSTATUS Status;
+ PVOID PAddress;
+ ULONG Consumer;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ LARGE_INTEGER FileOffset, TotalOffset;
+ ULONG Entry;
+ ULONG Attributes;
+ PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+
+ DPRINT("Not Present: %p %p (%p-%p)\n", AddressSpace, Address, MemoryArea->StartingAddress, MemoryArea->EndingAddress);
+
+ /*
+ * There is a window between taking the page fault and locking the
+ * address space when another thread could load the page so we check
+ * that.
+ */
+ if (MmIsPagePresent(Process, Address))
+ {
+ DPRINT("Done\n");
+ return(STATUS_SUCCESS);
+ }
+
+ PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
+ TotalOffset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress;
+
+ Segment = MemoryArea->Data.CacheData.Segment;
+
+ TotalOffset.QuadPart += MemoryArea->Data.CacheData.ViewOffset.QuadPart;
+ FileOffset = TotalOffset;
+
+ //Consumer = (Segment->Flags & MM_DATAFILE_SEGMENT) ? MC_CACHE : MC_USER;
+ Consumer = MC_CACHE;
+
+ if (Segment->FileObject)
+ {
+ DPRINT("FileName %wZ\n", &Segment->FileObject->FileName);
+ }
+
+ DPRINT("Total Offset %08x%08x\n", TotalOffset.HighPart, TotalOffset.LowPart);
+
+ /*
+ * Lock the segment
+ */
+ MmLockCacheSectionSegment(Segment);
+
+ /*
+ * Get the entry corresponding to the offset within the section
+ */
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, &TotalOffset);
+
+ Attributes = PAGE_READONLY;
+
+ if (Required->State && Required->Page[0])
+ {
+ DPRINT("Have file and page, set page %x in section @ %x #\n", Required->Page[0], TotalOffset.LowPart);
+
+ if (Required->SwapEntry)
+ MmSetSavedSwapEntryPage(Required->Page[0], Required->SwapEntry);
+
+ if (Required->State & 2)
+ {
+ DPRINT("Set in section @ %x\n", TotalOffset.LowPart);
+ Status = MiSetPageEntryCacheSectionSegment
+ (Segment, &TotalOffset, Entry = MAKE_PFN_SSE(Required->Page[0]));
+ if (!NT_SUCCESS(Status))
+ {
+ MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[0]);
+ }
+ MmUnlockCacheSectionSegment(Segment);
+ MiSetPageEvent(Process, Address);
+ DPRINT("Status %x\n", Status);
+ return STATUS_MM_RESTART_OPERATION;
+ }
+ else
+ {
+ DPRINT("Set %x in address space @ %x\n", Required->Page[0], Address);
+ Status = MmCreateVirtualMapping(Process, Address, Attributes, Required->Page, 1);
+ if (NT_SUCCESS(Status))
+ {
+ MmInsertRmap(Required->Page[0], Process, Address);
+ }
+ else
+ {
+ // Drop the reference for our address space ...
+ MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[0]);
+ }
+ MmUnlockCacheSectionSegment(Segment);
+ DPRINTC("XXX Set Event %x\n", Status);
+ MiSetPageEvent(Process, Address);
+ DPRINT("Status %x\n", Status);
+ return Status;
+ }
+ }
+ else if (Entry)
+ {
+ PFN_NUMBER Page = PFN_FROM_SSE(Entry);
+ DPRINT("Take reference to page %x #\n", Page);
+
+ MmReferencePage(Page);
+
+ Status = MmCreateVirtualMapping(Process, Address, Attributes, &Page, 1);
+ if (NT_SUCCESS(Status))
+ {
+ MmInsertRmap(Page, Process, Address);
+ }
+ DPRINT("XXX Set Event %x\n", Status);
+ MiSetPageEvent(Process, Address);
+ MmUnlockCacheSectionSegment(Segment);
+ DPRINT("Status %x\n", Status);
+ return Status;
+ }
+ else
+ {
+ DPRINT("Get page into section\n");
+ /*
+ * If the entry is zero (and it can't change because we have
+ * locked the segment) then we need to load the page.
+ */
+ //DPRINT1("Read from file %08x %wZ\n", FileOffset.LowPart, &Section->FileObject->FileName);
+ Required->State = 2;
+ Required->Context = Segment->FileObject;
+ Required->Consumer = Consumer;
+ Required->FileOffset = FileOffset;
+ Required->Amount = PAGE_SIZE;
+ Required->DoAcquisition = MiReadFilePage;
+ MiSetPageEntryCacheSectionSegment(Segment, &TotalOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
+ MmUnlockCacheSectionSegment(Segment);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ ASSERT(FALSE);
+ return STATUS_ACCESS_VIOLATION;
+}
+
+NTSTATUS
+NTAPI
+MiCopyPageToPage(PFN_NUMBER DestPage, PFN_NUMBER SrcPage)
+{
+ PEPROCESS Process;
+ KIRQL Irql, Irql2;
+ PVOID TempAddress, TempSource;
+
+ Process = PsGetCurrentProcess();
+ TempAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
+ if (TempAddress == NULL)
+ {
+ return(STATUS_NO_MEMORY);
+ }
+ TempSource = MiMapPageInHyperSpace(Process, SrcPage, &Irql2);
+ if (!TempSource) {
+ MiUnmapPageInHyperSpace(Process, TempAddress, Irql);
+ return(STATUS_NO_MEMORY);
+ }
+
+ memcpy(TempAddress, TempSource, PAGE_SIZE);
+
+ MiUnmapPageInHyperSpace(Process, TempSource, Irql2);
+ MiUnmapPageInHyperSpace(Process, TempAddress, Irql);
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+NTAPI
+MiCowCacheSectionPage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PVOID Address,
+ BOOLEAN Locked,
+ PMM_REQUIRED_RESOURCES Required)
+{
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ PFN_NUMBER NewPage, OldPage;
+ NTSTATUS Status;
+ PVOID PAddress;
+ LARGE_INTEGER Offset;
+ PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+
+ DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address, Locked);
+
+ Segment = MemoryArea->Data.CacheData.Segment;
+
+ /*
+ * Lock the segment
+ */
+ MmLockCacheSectionSegment(Segment);
+
+ /*
+ * Find the offset of the page
+ */
+ PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
+ Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress +
+ MemoryArea->Data.CacheData.ViewOffset.QuadPart;
+
+ if (!Required->Page[0])
+ {
+ SWAPENTRY SwapEntry;
+ if (MmIsPageSwapEntry(Process, Address))
+ {
+ MmGetPageFileMapping(Process, Address, &SwapEntry);
+ MmUnlockCacheSectionSegment(Segment);
+ if (SwapEntry == MM_WAIT_ENTRY)
+ return STATUS_SUCCESS + 1; // Wait ... somebody else is getting it right now
+ else
+ return STATUS_SUCCESS; // Nonwait swap entry ... handle elsewhere
+ }
+ Required->Page[1] = MmGetPfnForProcess(Process, Address);
+ Required->Consumer = MC_CACHE;
+ Required->Amount = 1;
+ Required->File = __FILE__;
+ Required->Line = __LINE__;
+ Required->DoAcquisition = MiGetOnePage;
+ MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
+ MmUnlockCacheSectionSegment(Segment);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ NewPage = Required->Page[0];
+ OldPage = Required->Page[1];
+
+ DPRINT("Allocated page %x\n", NewPage);
+
+ /*
+ * Unshare the old page.
+ */
+ MmDeleteRmap(OldPage, Process, PAddress);
+
+ /*
+ * Copy the old page
+ */
+ DPRINT("Copying\n");
+ MiCopyPageToPage(NewPage, OldPage);
+
+ /*
+ * Set the PTE to point to the new page
+ */
+ Status = MmCreateVirtualMapping
+ (Process, Address, PAGE_READWRITE, &NewPage, 1);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
+ ASSERT(FALSE);
+ MmUnlockCacheSectionSegment(Segment);
+ return(Status);
+ }
+
+ MmInsertRmap(NewPage, Process, PAddress);
+ MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
+ MmUnlockCacheSectionSegment(Segment);
+
+ DPRINT("Address 0x%.8X\n", Address);
+ return(STATUS_SUCCESS);
+}
+
+KEVENT MmWaitPageEvent;
+
+typedef struct _WORK_QUEUE_WITH_CONTEXT
+{
+ WORK_QUEUE_ITEM WorkItem;
+ PMMSUPPORT AddressSpace;
+ PMEMORY_AREA MemoryArea;
+ PMM_REQUIRED_RESOURCES Required;
+ NTSTATUS Status;
+ KEVENT Wait;
+ AcquireResource DoAcquisition;
+} WORK_QUEUE_WITH_CONTEXT, *PWORK_QUEUE_WITH_CONTEXT;
+
+VOID
+NTAPI
+MmpFaultWorker
+(PWORK_QUEUE_WITH_CONTEXT WorkItem)
+{
+ DPRINT("Calling work\n");
+ WorkItem->Status =
+ WorkItem->Required->DoAcquisition
+ (WorkItem->AddressSpace,
+ WorkItem->MemoryArea,
+ WorkItem->Required);
+ DPRINT("Status %x\n", WorkItem->Status);
+ KeSetEvent(&WorkItem->Wait, IO_NO_INCREMENT, FALSE);
+}
+
+NTSTATUS
+NTAPI
+MmpSectionAccessFaultInner
+(KPROCESSOR_MODE Mode,
+ PMMSUPPORT AddressSpace,
+ ULONG_PTR Address,
+ BOOLEAN FromMdl,
+ PETHREAD Thread)
+{
+ MEMORY_AREA* MemoryArea;
+ NTSTATUS Status;
+ BOOLEAN Locked = FromMdl;
+ MM_REQUIRED_RESOURCES Resources = { 0 };
+
+ DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
+
+ if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
+ {
+ DPRINT1("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * Find the memory area for the faulting address
+ */
+ if (Address >= (ULONG_PTR)MmSystemRangeStart)
+ {
+ /*
+ * Check permissions
+ */
+ if (Mode != KernelMode)
+ {
+ DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
+ return(STATUS_ACCESS_VIOLATION);
+ }
+ AddressSpace = MmGetKernelAddressSpace();
+ }
+ else
+ {
+ AddressSpace = &PsGetCurrentProcess()->Vm;
+ }
+
+ if (!FromMdl)
+ {
+ MmLockAddressSpace(AddressSpace);
+ }
+
+ do
+ {
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
+ if (MemoryArea == NULL ||
+ MemoryArea->DeleteInProgress)
+ {
+ if (!FromMdl)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ }
+ DPRINT("Address: %x\n", Address);
+ return (STATUS_ACCESS_VIOLATION);
+ }
+
+ DPRINT
+ ("Type %x (%x -> %x)\n",
+ MemoryArea->Type,
+ MemoryArea->StartingAddress,
+ MemoryArea->EndingAddress);
+
+ Resources.DoAcquisition = NULL;
+
+ // Note: fault handlers are called with address space locked
+ // We return STATUS_MORE_PROCESSING_REQUIRED if anything is needed
+ Status = MiCowCacheSectionPage
+ (AddressSpace, MemoryArea, (PVOID)Address, Locked, &Resources);
+
+ if (!FromMdl)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ }
+
+ if (Status == STATUS_SUCCESS + 1)
+ {
+ // Wait page ...
+ DPRINT("Waiting for %x\n", Address);
+ MiWaitForPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address);
+ DPRINT("Restarting fault %x\n", Address);
+ Status = STATUS_MM_RESTART_OPERATION;
+ }
+ else if (Status == STATUS_MM_RESTART_OPERATION)
+ {
+ // Clean slate
+ RtlZeroMemory(&Resources, sizeof(Resources));
+ }
+ else if (Status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ if (Thread->ActiveFaultCount > 0)
+ {
+ WORK_QUEUE_WITH_CONTEXT Context = { };
+ DPRINT("Already fault handling ... going to work item (%x)\n", Address);
+ Context.AddressSpace = AddressSpace;
+ Context.MemoryArea = MemoryArea;
+ Context.Required = &Resources;
+ KeInitializeEvent(&Context.Wait, NotificationEvent, FALSE);
+ ExInitializeWorkItem(&Context.WorkItem, (PWORKER_THREAD_ROUTINE)MmpFaultWorker, &Context);
+ DPRINT("Queue work item\n");
+ ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
+ DPRINT("Wait\n");
+ KeWaitForSingleObject(&Context.Wait, 0, KernelMode, FALSE, NULL);
+ Status = Context.Status;
+ DPRINT("Status %x\n", Status);
+ }
+ else
+ {
+ Status = Resources.DoAcquisition(AddressSpace, MemoryArea, &Resources);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = STATUS_MM_RESTART_OPERATION;
+ }
+ }
+
+ if (!FromMdl)
+ {
+ MmLockAddressSpace(AddressSpace);
+ }
+ }
+ while (Status == STATUS_MM_RESTART_OPERATION);
+
+ if (!NT_SUCCESS(Status) && MemoryArea->Type == 1)
+ {
+ DPRINT1("Completed page fault handling %x %x\n", Address, Status);
+ DPRINT1
+ ("Type %x (%x -> %x)\n",
+ MemoryArea->Type,
+ MemoryArea->StartingAddress,
+ MemoryArea->EndingAddress);
+ }
+
+ if (!FromMdl)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ }
+
+ return(Status);
+}
+
+NTSTATUS
+NTAPI
+MmAccessFaultCacheSection
+(KPROCESSOR_MODE Mode,
+ ULONG_PTR Address,
+ BOOLEAN FromMdl)
+{
+ PETHREAD Thread;
+ PMMSUPPORT AddressSpace;
+ NTSTATUS Status;
+
+ DPRINT("MmpAccessFault(Mode %d, Address %x)\n", Mode, Address);
+
+ Thread = PsGetCurrentThread();
+
+ if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
+ {
+ DPRINT1("Page fault at high IRQL %d, address %x\n", KeGetCurrentIrql(), Address);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * Find the memory area for the faulting address
+ */
+ if (Address >= (ULONG_PTR)MmSystemRangeStart)
+ {
+ /*
+ * Check permissions
+ */
+ if (Mode != KernelMode)
+ {
+ DPRINT1("Address: %x:%x\n", PsGetCurrentProcess(), Address);
+ return(STATUS_ACCESS_VIOLATION);
+ }
+ AddressSpace = MmGetKernelAddressSpace();
+ }
+ else
+ {
+ AddressSpace = &PsGetCurrentProcess()->Vm;
+ }
+
+ Thread->ActiveFaultCount++;
+ Status = MmpSectionAccessFaultInner(Mode, AddressSpace, Address, FromMdl, Thread);
+ Thread->ActiveFaultCount--;
+
+ return(Status);
+}
+
+NTSTATUS
+NTAPI
+MmNotPresentFaultCacheSectionInner
+(KPROCESSOR_MODE Mode,
+ PMMSUPPORT AddressSpace,
+ ULONG_PTR Address,
+ BOOLEAN FromMdl,
+ PETHREAD Thread)
+{
+ BOOLEAN Locked = FromMdl;
+ PMEMORY_AREA MemoryArea;
+ MM_REQUIRED_RESOURCES Resources = { 0 };
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!FromMdl)
+ {
+ MmLockAddressSpace(AddressSpace);
+ }
+
+ /*
+ * Call the memory area specific fault handler
+ */
+ do
+ {
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
+ if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
+ {
+ Status = STATUS_ACCESS_VIOLATION;
+ if (MemoryArea)
+ {
+ DPRINT1("Type %x DIP %x\n", MemoryArea->Type, MemoryArea->DeleteInProgress);
+ }
+ else
+ {
+ DPRINT1("No memory area\n");
+ }
+ DPRINT1("Process %x, Address %x\n", MmGetAddressSpaceOwner(AddressSpace), Address);
+ break;
+ }
+
+ DPRINTC
+ ("Type %x (%x -> %x -> %x) in %x\n",
+ MemoryArea->Type,
+ MemoryArea->StartingAddress,
+ Address,
+ MemoryArea->EndingAddress,
+ PsGetCurrentThread());
+
+ Resources.DoAcquisition = NULL;
+
+ // Note: fault handlers are called with address space locked
+ // We return STATUS_MORE_PROCESSING_REQUIRED if anything is needed
+
+ Status = MmNotPresentFaultCachePage
+ (AddressSpace, MemoryArea, (PVOID)Address, Locked, &Resources);
+
+ if (!FromMdl)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ }
+
+ if (Status == STATUS_SUCCESS)
+ {
+ ; // Nothing
+ }
+ else if (Status == STATUS_SUCCESS + 1)
+ {
+ // Wait page ...
+ DPRINT("Waiting for %x\n", Address);
+ MiWaitForPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address);
+ DPRINT("Done waiting for %x\n", Address);
+ Status = STATUS_MM_RESTART_OPERATION;
+ }
+ else if (Status == STATUS_MM_RESTART_OPERATION)
+ {
+ // Clean slate
+ DPRINT("Clear resource\n");
+ RtlZeroMemory(&Resources, sizeof(Resources));
+ }
+ else if (Status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ if (Thread->ActiveFaultCount > 1)
+ {
+ WORK_QUEUE_WITH_CONTEXT Context = { };
+ DPRINTC("Already fault handling ... going to work item (%x)\n", Address);
+ Context.AddressSpace = AddressSpace;
+ Context.MemoryArea = MemoryArea;
+ Context.Required = &Resources;
+ KeInitializeEvent(&Context.Wait, NotificationEvent, FALSE);
+ ExInitializeWorkItem(&Context.WorkItem, (PWORKER_THREAD_ROUTINE)MmpFaultWorker, &Context);
+ DPRINT("Queue work item\n");
+ ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
+ DPRINT("Wait\n");
+ KeWaitForSingleObject(&Context.Wait, 0, KernelMode, FALSE, NULL);
+ Status = Context.Status;
+ DPRINTC("Status %x\n", Status);
+ }
+ else
+ {
+ DPRINT("DoAcquisition %x\n", Resources.DoAcquisition);
+ Status = Resources.DoAcquisition
+ (AddressSpace, MemoryArea, &Resources);
+ DPRINT("DoAcquisition %x -> %x\n", Resources.DoAcquisition, Status);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = STATUS_MM_RESTART_OPERATION;
+ }
+ }
+ else if (NT_SUCCESS(Status))
+ {
+ ASSERT(FALSE);
+ }
+
+ if (!FromMdl)
+ {
+ MmLockAddressSpace(AddressSpace);
+ }
+ }
+ while (Status == STATUS_MM_RESTART_OPERATION);
+
+ DPRINTC("Completed page fault handling: %x:%x %x\n", MmGetAddressSpaceOwner(AddressSpace), Address, Status);
+ if (!FromMdl)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ }
+
+ MiSetPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address);
+ DPRINT("Done %x\n", Status);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MmNotPresentFaultCacheSection
+(KPROCESSOR_MODE Mode,
+ ULONG_PTR Address,
+ BOOLEAN FromMdl)
+{
+ PETHREAD Thread;
+ PMMSUPPORT AddressSpace;
+ NTSTATUS Status;
+
+ Address &= ~(PAGE_SIZE - 1);
+ DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
+
+ Thread = PsGetCurrentThread();
+
+ if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
+ {
+ DPRINT1("Page fault at high IRQL %d, address %x\n", KeGetCurrentIrql(), Address);
+ ASSERT(FALSE);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ /*
+ * Find the memory area for the faulting address
+ */
+ if (Address >= (ULONG_PTR)MmSystemRangeStart)
+ {
+ /*
+ * Check permissions
+ */
+ if (Mode != KernelMode)
+ {
+ DPRINTC("Address: %x\n", Address);
+ return(STATUS_ACCESS_VIOLATION);
+ }
+ AddressSpace = MmGetKernelAddressSpace();
+ }
+ else
+ {
+ AddressSpace = &PsGetCurrentProcess()->Vm;
+ }
+
+ Thread->ActiveFaultCount++;
+ Status = MmNotPresentFaultCacheSectionInner
+ (Mode, AddressSpace, Address, FromMdl, Thread);
+ Thread->ActiveFaultCount--;
+
+ ASSERT(Status != STATUS_UNSUCCESSFUL);
+ ASSERT(Status != STATUS_INVALID_PARAMETER);
+ DPRINT("MmAccessFault %x:%x -> %x\n", MmGetAddressSpaceOwner(AddressSpace), Address, Status);
+
+ return(Status);
+}
diff --git a/reactos/ntoskrnl/cache/section/io.c b/reactos/ntoskrnl/cache/section/io.c
new file mode 100644
index 00000000000..254c25c38a6
--- /dev/null
+++ b/reactos/ntoskrnl/cache/section/io.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/section.c
+ * PURPOSE: Implements section objects
+ *
+ * PROGRAMMERS: Rex Jolliff
+ * David Welch
+ * Eric Kohl
+ * Emanuele Aliberti
+ * Eugene Ingerman
+ * Casper Hornstrup
+ * KJK::Hyperion
+ * Guido de Jong
+ * Ge van Geldorp
+ * Royce Mitchell III
+ * Filip Navara
+ * Aleksey Bragin
+ * Jason Filby
+ * Thomas Weidenmueller
+ * Gunnar Andre' Dalsnes
+ * Mike Nordell
+ * Alex Ionescu
+ * Gregor Anich
+ * Steven Edwards
+ * Herve Poussineau
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include
+#include "newmm.h"
+#define NDEBUG
+#include
+#include
+
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
+#pragma alloc_text(INIT, MmInitSectionImplementation)
+#endif
+
+KEVENT CcpLazyWriteEvent;
+
+PDEVICE_OBJECT
+NTAPI
+MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject)
+{
+ return IoGetRelatedDeviceObject(FileObject);
+}
+
+NTSTATUS
+NTAPI
+MiSimpleReadComplete
+(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context)
+{
+ /* Unlock MDL Pages, page 167. */
+ DPRINT("MiSimpleReadComplete %x\n", Irp);
+ PMDL Mdl = Irp->MdlAddress;
+ while (Mdl)
+ {
+ DPRINT("MDL Unlock %x\n", Mdl);
+ MmUnlockPages(Mdl);
+ Mdl = Mdl->Next;
+ }
+
+ /* Check if there's an MDL */
+ while ((Mdl = Irp->MdlAddress))
+ {
+ /* Clear all of them */
+ Irp->MdlAddress = Mdl->Next;
+ IoFreeMdl(Mdl);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MiSimpleRead
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ PVOID Buffer,
+ ULONG Length,
+ PIO_STATUS_BLOCK ReadStatus)
+{
+ NTSTATUS Status;
+ PIRP Irp = NULL;
+ KEVENT ReadWait;
+ PDEVICE_OBJECT DeviceObject;
+ PIO_STACK_LOCATION IrpSp;
+
+ ASSERT(FileObject);
+ ASSERT(FileOffset);
+ ASSERT(Buffer);
+ ASSERT(ReadStatus);
+
+ DeviceObject = MmGetDeviceObjectForFile(FileObject);
+ ReadStatus->Status = STATUS_INTERNAL_ERROR;
+ ReadStatus->Information = 0;
+
+ ASSERT(DeviceObject);
+
+ DPRINT
+ ("PAGING READ: FileObject %x <%wZ> Offset %08x%08x Length %d\n",
+ &FileObject,
+ &FileObject->FileName,
+ FileOffset->HighPart,
+ FileOffset->LowPart,
+ Length);
+
+ KeInitializeEvent(&ReadWait, NotificationEvent, FALSE);
+
+ Irp = IoBuildAsynchronousFsdRequest
+ (IRP_MJ_READ,
+ DeviceObject,
+ Buffer,
+ Length,
+ FileOffset,
+ ReadStatus);
+
+ if (!Irp)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ Irp->Flags |= IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_API;
+
+ Irp->UserEvent = &ReadWait;
+ Irp->Tail.Overlay.OriginalFileObject = FileObject;
+ Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ IrpSp = IoGetNextIrpStackLocation(Irp);
+ IrpSp->Control |= SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
+ IrpSp->FileObject = FileObject;
+ IrpSp->CompletionRoutine = MiSimpleReadComplete;
+
+ Status = IoCallDriver(DeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ DPRINT1("KeWaitForSingleObject(&ReadWait)\n");
+ if (!NT_SUCCESS
+ (KeWaitForSingleObject
+ (&ReadWait,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL)))
+ {
+ DPRINT1("Warning: Failed to wait for synchronous IRP\n");
+ ASSERT(FALSE);
+ return Status;
+ }
+ }
+
+ DPRINT("Paging IO Done: %08x\n", ReadStatus->Status);
+ Status =
+ ReadStatus->Status == STATUS_END_OF_FILE ?
+ STATUS_SUCCESS : ReadStatus->Status;
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+_MiSimpleWrite
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ PVOID Buffer,
+ ULONG Length,
+ PIO_STATUS_BLOCK ReadStatus,
+ const char *File,
+ int Line)
+{
+ NTSTATUS Status;
+ PIRP Irp = NULL;
+ KEVENT ReadWait;
+ PDEVICE_OBJECT DeviceObject;
+ PIO_STACK_LOCATION IrpSp;
+
+ ASSERT(FileObject);
+ ASSERT(FileOffset);
+ ASSERT(Buffer);
+ ASSERT(ReadStatus);
+
+ ObReferenceObject(FileObject);
+ DeviceObject = MmGetDeviceObjectForFile(FileObject);
+ ASSERT(DeviceObject);
+
+ DPRINT
+ ("PAGING WRITE: FileObject %x Offset %x Length %d (%s:%d)\n",
+ &FileObject,
+ FileOffset->LowPart,
+ Length,
+ File,
+ Line);
+
+ KeInitializeEvent(&ReadWait, NotificationEvent, FALSE);
+
+ Irp = IoBuildAsynchronousFsdRequest
+ (IRP_MJ_WRITE,
+ DeviceObject,
+ Buffer,
+ Length,
+ FileOffset,
+ ReadStatus);
+
+ if (!Irp)
+ {
+ ObDereferenceObject(FileObject);
+ return STATUS_NO_MEMORY;
+ }
+
+ Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_API;
+
+ Irp->UserEvent = &ReadWait;
+ Irp->Tail.Overlay.OriginalFileObject = FileObject;
+ Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ IrpSp = IoGetNextIrpStackLocation(Irp);
+ IrpSp->Control |= SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
+ IrpSp->FileObject = FileObject;
+ IrpSp->CompletionRoutine = MiSimpleReadComplete;
+
+ DPRINT("Call Driver\n");
+ Status = IoCallDriver(DeviceObject, Irp);
+ DPRINT("Status %x\n", Status);
+
+ ObDereferenceObject(FileObject);
+
+ if (Status == STATUS_PENDING)
+ {
+ DPRINT1("KeWaitForSingleObject(&ReadWait)\n");
+ if (!NT_SUCCESS
+ (KeWaitForSingleObject
+ (&ReadWait,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL)))
+ {
+ DPRINT1("Warning: Failed to wait for synchronous IRP\n");
+ ASSERT(FALSE);
+ return Status;
+ }
+ }
+
+ DPRINT("Paging IO Done: %08x\n", ReadStatus->Status);
+ return ReadStatus->Status;
+}
+
+extern KEVENT MpwThreadEvent;
+FAST_MUTEX MiWriteMutex;
+
+NTSTATUS
+NTAPI
+_MiWriteBackPage
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ ULONG Length,
+ PFN_NUMBER Page,
+ const char *File,
+ int Line)
+{
+ NTSTATUS Status;
+ PVOID Hyperspace;
+ IO_STATUS_BLOCK Iosb;
+ KIRQL OldIrql;
+ PVOID PageBuffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
+
+ if (!PageBuffer) return STATUS_NO_MEMORY;
+
+ OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
+ Hyperspace = MmCreateHyperspaceMapping(Page);
+ RtlCopyMemory(PageBuffer, Hyperspace, PAGE_SIZE);
+ MmDeleteHyperspaceMapping(Hyperspace);
+ KfLowerIrql(OldIrql);
+
+ DPRINT1("MiWriteBackPage(%wZ,%08x%08x,%s:%d)\n", &FileObject->FileName, FileOffset->u.HighPart, FileOffset->u.LowPart, File, Line);
+ Status = MiSimpleWrite
+ (FileObject,
+ FileOffset,
+ PageBuffer,
+ Length,
+ &Iosb);
+
+ ExFreePool(PageBuffer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MiSimpleWrite failed (%x)\n", Status);
+ }
+
+ return Status;
+}
diff --git a/reactos/ntoskrnl/cache/section/newmm.h b/reactos/ntoskrnl/cache/section/newmm.h
new file mode 100644
index 00000000000..43fd3fe7cef
--- /dev/null
+++ b/reactos/ntoskrnl/cache/section/newmm.h
@@ -0,0 +1,454 @@
+#pragma once
+
+#include
+
+/* TYPES *********************************************************************/
+
+#define MM_WAIT_ENTRY 0x7ffff800
+#define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
+#define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
+#define MM_IS_WAIT_PTE(E) \
+ (IS_SWAP_FROM_SSE(E) && SWAPENTRY_FROM_SSE(E) == MM_WAIT_ENTRY)
+#define MAKE_PFN_SSE(P) ((P) << PAGE_SHIFT)
+#define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
+#define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
+#define DIRTY_SSE(E) ((E) | 2)
+#define CLEAN_SSE(E) ((E) & ~2)
+#define IS_DIRTY_SSE(E) ((E) & 2)
+
+#define MEMORY_AREA_CACHE (2)
+#define MM_SEGMENT_FINALIZE (0x40000000)
+
+#define RMAP_SEGMENT_MASK ~0xff
+#define RMAP_IS_SEGMENT(x) (((ULONG_PTR)(x) & RMAP_SEGMENT_MASK) == RMAP_SEGMENT_MASK)
+
+#define MIN(x,y) (((x)<(y))?(x):(y))
+#define MAX(x,y) (((x)>(y))?(x):(y))
+
+/* Determine what's needed to make paged pool fit in this category.
+ * it seems that something more is required to satisfy arm3. */
+#define BALANCER_CAN_EVICT(Consumer) \
+ (((Consumer) == MC_USER) || \
+ ((Consumer) == MC_CACHE))
+
+#define SEC_CACHE (0x40000000)
+
+#define MiWaitForPageEvent(Process,Address) do { \
+ DPRINT("MiWaitForPageEvent %x:%x #\n", Process, Address); \
+ KeWaitForSingleObject(&MmWaitPageEvent, 0, KernelMode, FALSE, NULL); \
+} while(0)
+
+#define MiSetPageEvent(Process,Address) do { \
+ DPRINT("MiSetPageEvent %x:%x #\n",Process, Address); \
+ KeSetEvent(&MmWaitPageEvent, IO_NO_INCREMENT, FALSE); \
+} while(0)
+
+/* We store 8 bits of location with a page association */
+#define ENTRIES_PER_ELEMENT 256
+
+extern KEVENT MmWaitPageEvent;
+
+typedef struct _MM_CACHE_SECTION_SEGMENT
+{
+ FAST_MUTEX Lock; /* lock which protects the page directory */
+ PFILE_OBJECT FileObject;
+ ULARGE_INTEGER RawLength; /* length of the segment which is part of the mapped file */
+ ULARGE_INTEGER Length; /* absolute length of the segment */
+ ULONG ReferenceCount;
+ ULONG Protection;
+ ULONG Flags;
+ BOOLEAN WriteCopy;
+
+ struct
+ {
+ LONG FileOffset; /* start offset into the file for image sections */
+ ULONG_PTR VirtualAddress; /* dtart offset into the address range for image sections */
+ ULONG Characteristics;
+ } Image;
+
+ RTL_GENERIC_TABLE PageTable;
+} MM_CACHE_SECTION_SEGMENT, *PMM_CACHE_SECTION_SEGMENT;
+
+typedef struct _CACHE_SECTION_PAGE_TABLE
+{
+ LARGE_INTEGER FileOffset;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ ULONG Refcount;
+ ULONG PageEntries[ENTRIES_PER_ELEMENT];
+} CACHE_SECTION_PAGE_TABLE, *PCACHE_SECTION_PAGE_TABLE;
+
+struct _MM_REQUIRED_RESOURCES;
+
+typedef NTSTATUS (NTAPI * AcquireResource)
+ (PMMSUPPORT AddressSpace,
+ struct _MEMORY_AREA *MemoryArea,
+ struct _MM_REQUIRED_RESOURCES *Required);
+typedef NTSTATUS (NTAPI * NotPresentFaultHandler)
+ (PMMSUPPORT AddressSpace,
+ struct _MEMORY_AREA *MemoryArea,
+ PVOID Address,
+ BOOLEAN Locked,
+ struct _MM_REQUIRED_RESOURCES *Required);
+typedef NTSTATUS (NTAPI * FaultHandler)
+ (PMMSUPPORT AddressSpace,
+ struct _MEMORY_AREA *MemoryArea,
+ PVOID Address,
+ struct _MM_REQUIRED_RESOURCES *Required);
+
+typedef struct _MM_REQUIRED_RESOURCES
+{
+ ULONG Consumer;
+ ULONG Amount;
+ ULONG Offset;
+ ULONG State;
+ PVOID Context;
+ LARGE_INTEGER FileOffset;
+ AcquireResource DoAcquisition;
+ PFN_NUMBER Page[2];
+ PVOID Buffer[2];
+ SWAPENTRY SwapEntry;
+ const char *File;
+ int Line;
+} MM_REQUIRED_RESOURCES, *PMM_REQUIRED_RESOURCES;
+
+PFN_NUMBER
+NTAPI
+MmWithdrawSectionPage
+(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, BOOLEAN *Dirty);
+
+NTSTATUS
+NTAPI
+MmFinalizeSectionPageOut
+(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, PFN_NUMBER Page,
+ BOOLEAN Dirty);
+
+/* sptab.c *******************************************************************/
+
+VOID
+NTAPI
+MiInitializeSectionPageTable(PMM_CACHE_SECTION_SEGMENT Segment);
+
+NTSTATUS
+NTAPI
+_MiSetPageEntryCacheSectionSegment
+(PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER Offset,
+ ULONG Entry, const char *file, int line);
+
+ULONG
+NTAPI
+_MiGetPageEntryCacheSectionSegment
+(PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER Offset, const char *file, int line);
+
+#define MiSetPageEntryCacheSectionSegment(S,O,E) _MiSetPageEntryCacheSectionSegment(S,O,E,__FILE__,__LINE__)
+#define MiGetPageEntryCacheSectionSegment(S,O) _MiGetPageEntryCacheSectionSegment(S,O,__FILE__,__LINE__)
+
+typedef VOID (NTAPI *FREE_SECTION_PAGE_FUN)
+ (PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER Offset);
+
+VOID
+NTAPI
+MiFreePageTablesSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, FREE_SECTION_PAGE_FUN FreePage);
+
+/* Yields a lock */
+PMM_CACHE_SECTION_SEGMENT
+NTAPI
+MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset);
+
+NTSTATUS
+NTAPI
+MmSetSectionAssociation(PFN_NUMBER Page, PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset);
+
+VOID
+NTAPI
+MmDeleteSectionAssociation(PFN_NUMBER Page);
+
+NTSTATUS
+NTAPI
+MmpPageOutPhysicalAddress(PFN_NUMBER Page);
+
+/* io.c **********************************************************************/
+
+NTSTATUS
+MmspWaitForFileLock(PFILE_OBJECT File);
+
+NTSTATUS
+NTAPI
+MiSimpleRead
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ PVOID Buffer,
+ ULONG Length,
+ PIO_STATUS_BLOCK ReadStatus);
+
+NTSTATUS
+NTAPI
+_MiSimpleWrite
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ PVOID Buffer,
+ ULONG Length,
+ PIO_STATUS_BLOCK ReadStatus,
+ const char *file,
+ int line);
+
+#define MiSimpleWrite(F,O,B,L,R) _MiSimpleWrite(F,O,B,L,R,__FILE__,__LINE__)
+
+NTSTATUS
+NTAPI
+_MiWriteBackPage
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER Offset,
+ ULONG Length,
+ PFN_NUMBER Page,
+ const char *File,
+ int Line);
+
+#define MiWriteBackPage(F,O,L,P) _MiWriteBackPage(F,O,L,P,__FILE__,__LINE__)
+
+/* section.c *****************************************************************/
+
+NTSTATUS
+NTAPI
+MmAccessFaultCacheSection
+(KPROCESSOR_MODE Mode,
+ ULONG_PTR Address,
+ BOOLEAN FromMdl);
+
+NTSTATUS
+NTAPI
+MiReadFilePage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES RequiredResources);
+
+ULONG
+NTAPI
+MiChecksumPage(PFN_NUMBER Page, BOOLEAN Lock);
+
+NTSTATUS
+NTAPI
+MiGetOnePage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES RequiredResources);
+
+NTSTATUS
+NTAPI
+MiSwapInPage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES RequiredResources);
+
+NTSTATUS
+NTAPI
+MiWriteSwapPage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES Resources);
+
+NTSTATUS
+NTAPI
+MiWriteFilePage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES Resources);
+
+VOID
+NTAPI
+MiFreeSegmentPage
+(PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER FileOffset);
+
+NTSTATUS
+NTAPI
+MiCowCacheSectionPage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PVOID Address,
+ BOOLEAN Locked,
+ PMM_REQUIRED_RESOURCES Required);
+
+NTSTATUS
+NTAPI
+MiZeroFillSection(PVOID Address, PLARGE_INTEGER FileOffsetPtr, ULONG Length);
+
+VOID
+MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address);
+
+VOID
+NTAPI
+_MmLockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line);
+
+#define MmLockCacheSectionSegment(x) _MmLockCacheSectionSegment(x,__FILE__,__LINE__)
+
+VOID
+NTAPI
+_MmUnlockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line);
+
+#define MmUnlockCacheSectionSegment(x) _MmUnlockCacheSectionSegment(x,__FILE__,__LINE__)
+
+VOID
+MmFreeCacheSectionPage
+(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
+ PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty);
+
+NTSTATUS
+NTAPI
+_MiFlushMappedSection(PVOID BaseAddress, PLARGE_INTEGER BaseOffset, PLARGE_INTEGER FileSize, BOOLEAN Dirty, const char *File, int Line);
+
+#define MiFlushMappedSection(A,O,S,D) _MiFlushMappedSection(A,O,S,D,__FILE__,__LINE__)
+
+VOID
+NTAPI
+MmFinalizeSegment(PMM_CACHE_SECTION_SEGMENT Segment);
+
+VOID
+NTAPI
+MmFreeSectionSegments(PFILE_OBJECT FileObject);
+
+NTSTATUS NTAPI
+MmMapCacheViewInSystemSpaceAtOffset
+(IN PMM_CACHE_SECTION_SEGMENT Segment,
+ OUT PVOID * MappedBase,
+ IN PLARGE_INTEGER ViewOffset,
+ IN OUT PULONG ViewSize);
+
+NTSTATUS
+NTAPI
+_MiMapViewOfSegment
+(PMMSUPPORT AddressSpace,
+ PMM_CACHE_SECTION_SEGMENT Segment,
+ PVOID* BaseAddress,
+ SIZE_T ViewSize,
+ ULONG Protect,
+ PLARGE_INTEGER ViewOffset,
+ ULONG AllocationType,
+ const char *file,
+ int line);
+
+#define MiMapViewOfSegment(AddressSpace,Segment,BaseAddress,ViewSize,Protect,ViewOffset,AllocationType) _MiMapViewOfSegment(AddressSpace,Segment,BaseAddress,ViewSize,Protect,ViewOffset,AllocationType,__FILE__,__LINE__)
+
+NTSTATUS
+NTAPI
+MmUnmapViewOfCacheSegment
+(PMMSUPPORT AddressSpace,
+ PVOID BaseAddress);
+
+NTSTATUS
+NTAPI
+MmUnmapCacheViewInSystemSpace(PVOID Address);
+
+NTSTATUS
+NTAPI
+MmNotPresentFaultCachePage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PVOID Address,
+ BOOLEAN Locked,
+ PMM_REQUIRED_RESOURCES Required);
+
+NTSTATUS
+NTAPI
+MmPageOutPageFileView
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PVOID Address,
+ PMM_REQUIRED_RESOURCES Required);
+
+FORCEINLINE
+BOOLEAN
+_MmTryToLockAddressSpace(IN PMMSUPPORT AddressSpace, const char *file, int line)
+{
+ BOOLEAN Result = KeTryToAcquireGuardedMutex(&CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock);
+ //DbgPrint("(%s:%d) Try Lock Address Space %x -> %s\n", file, line, AddressSpace, Result ? "true" : "false");
+ return Result;
+}
+
+#define MmTryToLockAddressSpace(x) _MmTryToLockAddressSpace(x,__FILE__,__LINE__)
+
+NTSTATUS
+NTAPI
+MiWidenSegment
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES RequiredResources);
+
+NTSTATUS
+NTAPI
+MiSwapInSectionPage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES RequiredResources);
+
+NTSTATUS
+NTAPI
+MmExtendCacheSection(PMM_CACHE_SECTION_SEGMENT Section, PLARGE_INTEGER NewSize, BOOLEAN ExtendFile);
+
+NTSTATUS
+NTAPI
+_MiFlushMappedSection(PVOID BaseAddress, PLARGE_INTEGER BaseOffset, PLARGE_INTEGER FileSize, BOOLEAN Dirty, const char *File, int Line);
+
+#define MiFlushMappedSection(A,O,S,D) _MiFlushMappedSection(A,O,S,D,__FILE__,__LINE__)
+
+NTSTATUS
+NTAPI
+MmCreateCacheSection
+(PMM_CACHE_SECTION_SEGMENT *SegmentObject,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ PLARGE_INTEGER UMaximumSize,
+ ULONG SectionPageProtection,
+ ULONG AllocationAttributes,
+ PFILE_OBJECT FileObject);
+
+NTSTATUS
+NTAPI
+MiSimpleRead
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ PVOID Buffer,
+ ULONG Length,
+ PIO_STATUS_BLOCK ReadStatus);
+
+NTSTATUS
+NTAPI
+_MiSimpleWrite
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER FileOffset,
+ PVOID Buffer,
+ ULONG Length,
+ PIO_STATUS_BLOCK ReadStatus,
+ const char *file,
+ int line);
+
+#define MiSimpleWrite(F,O,B,L,R) _MiSimpleWrite(F,O,B,L,R,__FILE__,__LINE__)
+
+NTSTATUS
+NTAPI
+_MiWriteBackPage
+(PFILE_OBJECT FileObject,
+ PLARGE_INTEGER Offset,
+ ULONG Length,
+ PFN_NUMBER Page,
+ const char *File,
+ int Line);
+
+#define MiWriteBackPage(F,O,L,P) _MiWriteBackPage(F,O,L,P,__FILE__,__LINE__)
+
+PVOID
+NTAPI
+MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset);
+
+NTSTATUS
+NTAPI
+MmNotPresentFaultCacheSection
+(KPROCESSOR_MODE Mode,
+ ULONG_PTR Address,
+ BOOLEAN FromMdl);
+
+ULONG
+NTAPI
+MiCacheEvictPages(PVOID BaseAddress, ULONG Target);
diff --git a/reactos/ntoskrnl/cache/section/reqtools.c b/reactos/ntoskrnl/cache/section/reqtools.c
new file mode 100644
index 00000000000..68056d49ec9
--- /dev/null
+++ b/reactos/ntoskrnl/cache/section/reqtools.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/section.c
+ * PURPOSE: Implements section objects
+ *
+ * PROGRAMMERS: Rex Jolliff
+ * David Welch
+ * Eric Kohl
+ * Emanuele Aliberti
+ * Eugene Ingerman
+ * Casper Hornstrup
+ * KJK::Hyperion
+ * Guido de Jong
+ * Ge van Geldorp
+ * Royce Mitchell III
+ * Filip Navara
+ * Aleksey Bragin
+ * Jason Filby
+ * Thomas Weidenmueller
+ * Gunnar Andre' Dalsnes
+ * Mike Nordell
+ * Alex Ionescu
+ * Gregor Anich
+ * Steven Edwards
+ * Herve Poussineau
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include
+#include "newmm.h"
+#define NDEBUG
+#include
+
+#define DPRINTC DPRINT
+
+NTSTATUS
+NTAPI
+MiGetOnePage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES Required)
+{
+ int i;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ for (i = 0; i < Required->Amount; i++)
+ {
+ DPRINTC("MiGetOnePage(%s:%d)\n", Required->File, Required->Line);
+ Status = MmRequestPageMemoryConsumer(Required->Consumer, TRUE, &Required->Page[i]);
+ if (!NT_SUCCESS(Status))
+ {
+ while (i > 0)
+ {
+ MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[i-1]);
+ i--;
+ }
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MiReadFilePage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES RequiredResources)
+{
+ PFILE_OBJECT FileObject = RequiredResources->Context;
+ PPFN_NUMBER Page = &RequiredResources->Page[RequiredResources->Offset];
+ PLARGE_INTEGER FileOffset = &RequiredResources->FileOffset;
+ NTSTATUS Status;
+ PVOID PageBuf = NULL;
+ PMEMORY_AREA TmpArea;
+ IO_STATUS_BLOCK IOSB;
+ PHYSICAL_ADDRESS BoundaryAddressMultiple;
+
+ BoundaryAddressMultiple.QuadPart = 0;
+
+ DPRINTC
+ ("Pulling page %08x%08x from %wZ to %x\n",
+ FileOffset->u.HighPart, FileOffset->u.LowPart,
+ &FileObject->FileName,
+ Page);
+
+ Status = MmRequestPageMemoryConsumer(RequiredResources->Consumer, TRUE, Page);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Status: %x\n", Status);
+ return Status;
+ }
+
+ MmLockAddressSpace(MmGetKernelAddressSpace());
+ Status = MmCreateMemoryArea
+ (MmGetKernelAddressSpace(),
+ MEMORY_AREA_VIRTUAL_MEMORY,
+ &PageBuf,
+ PAGE_SIZE,
+ PAGE_READWRITE,
+ &TmpArea,
+ FALSE,
+ MEM_TOP_DOWN,
+ BoundaryAddressMultiple);
+
+ DPRINT("Status %x, PageBuf %x\n", Status, PageBuf);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("STATUS_NO_MEMORY: %x\n", Status);
+ MmUnlockAddressSpace(MmGetKernelAddressSpace());
+ MmReleasePageMemoryConsumer(MC_CACHE, *Page);
+ return STATUS_NO_MEMORY;
+ }
+
+ Status = MmCreateVirtualMapping(NULL, PageBuf, PAGE_READWRITE, Page, 1);
+ if (!NT_SUCCESS(Status))
+ {
+ MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
+ MmUnlockAddressSpace(MmGetKernelAddressSpace());
+ MmReleasePageMemoryConsumer(MC_CACHE, *Page);
+ DPRINT1("Status: %x\n", Status);
+ return Status;
+ }
+
+ MmUnlockAddressSpace(MmGetKernelAddressSpace());
+
+ Status = MiSimpleRead
+ (FileObject,
+ FileOffset,
+ PageBuf,
+ RequiredResources->Amount,
+ &IOSB);
+ RtlZeroMemory
+ ((PCHAR)PageBuf+RequiredResources->Amount,
+ PAGE_SIZE-RequiredResources->Amount);
+
+ DPRINT("Read Status %x (Page %x)\n", Status, *Page);
+
+ MmLockAddressSpace(MmGetKernelAddressSpace());
+ MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
+ MmUnlockAddressSpace(MmGetKernelAddressSpace());
+
+ if (!NT_SUCCESS(Status))
+ {
+ MmReleasePageMemoryConsumer(MC_CACHE, *Page);
+ DPRINT("Status: %x\n", Status);
+ return Status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+ULONG
+NTAPI
+MiChecksumPage(PFN_NUMBER Page, BOOLEAN Lock)
+{
+ int i;
+ NTSTATUS Status;
+ ULONG Total = 0;
+ PULONG PageBuf = NULL;
+ PMEMORY_AREA TmpArea;
+ PHYSICAL_ADDRESS BoundaryAddressMultiple;
+
+ BoundaryAddressMultiple.QuadPart = 0;
+
+ if (Lock) MmLockAddressSpace(MmGetKernelAddressSpace());
+
+ Status = MmCreateMemoryArea
+ (MmGetKernelAddressSpace(),
+ MEMORY_AREA_VIRTUAL_MEMORY,
+ (PVOID*)&PageBuf,
+ PAGE_SIZE,
+ PAGE_READWRITE,
+ &TmpArea,
+ FALSE,
+ MEM_TOP_DOWN,
+ BoundaryAddressMultiple);
+
+ DPRINT("Status %x, PageBuf %x\n", Status, PageBuf);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("STATUS_NO_MEMORY: %x\n", Status);
+ if (Lock) MmUnlockAddressSpace(MmGetKernelAddressSpace());
+ return 0;
+ }
+
+ Status = MmCreateVirtualMapping(NULL, PageBuf, PAGE_READWRITE, &Page, 1);
+ if (!NT_SUCCESS(Status))
+ {
+ MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
+ if (Lock) MmUnlockAddressSpace(MmGetKernelAddressSpace());
+ DPRINT1("Status: %x\n", Status);
+ return Status;
+ }
+
+ for (i = 0; i < 1024; i++) {
+ Total += PageBuf[i];
+ }
+
+ MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
+ if (Lock) MmUnlockAddressSpace(MmGetKernelAddressSpace());
+
+ return Total;
+}
+
+NTSTATUS
+NTAPI
+MiSwapInPage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES Resources)
+{
+ NTSTATUS Status;
+
+ Status = MmRequestPageMemoryConsumer(Resources->Consumer, TRUE, &Resources->Page[Resources->Offset]);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status);
+ return Status;
+ }
+
+ Status = MmReadFromSwapPage(Resources->SwapEntry, Resources->Page[Resources->Offset]);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
+ return Status;
+ }
+
+ MmSetSavedSwapEntryPage(Resources->Page[Resources->Offset], Resources->SwapEntry);
+
+ DPRINT1("MiSwapInPage(%x,%x)\n", Resources->Page[Resources->Offset], Resources->SwapEntry);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MiWriteFilePage
+(PMMSUPPORT AddressSpace,
+ PMEMORY_AREA MemoryArea,
+ PMM_REQUIRED_RESOURCES Required)
+{
+ DPRINT1("MiWriteFilePage(%x,%x)\n", Required->Page[Required->Offset], Required->FileOffset.LowPart);
+
+ return MiWriteBackPage
+ (Required->Context,
+ &Required->FileOffset,
+ PAGE_SIZE,
+ Required->Page[Required->Offset]);
+}
diff --git a/reactos/ntoskrnl/cache/section/sptab.c b/reactos/ntoskrnl/cache/section/sptab.c
new file mode 100644
index 00000000000..0b71764b865
--- /dev/null
+++ b/reactos/ntoskrnl/cache/section/sptab.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/section.c
+ * PURPOSE: Section object page tables
+ *
+ * PROGRAMMERS: arty
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include
+#include "newmm.h"
+#define NDEBUG
+#include
+
+#define DPRINTC DPRINT
+
+/* TYPES *********************************************************************/
+
+extern KSPIN_LOCK MiSectionPageTableLock;
+
+static
+PVOID
+NTAPI
+MiSectionPageTableAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
+{
+ PVOID Result;
+ Result = ExAllocatePoolWithTag(NonPagedPool, Bytes, 'MmPt');
+ DPRINT("MiSectionPageTableAllocate(%d) => %p\n", Bytes, Result);
+ return Result;
+}
+
+static
+VOID
+NTAPI
+MiSectionPageTableFree(PRTL_GENERIC_TABLE Table, PVOID Data)
+{
+ DPRINT("MiSectionPageTableFree(%p)\n", Data);
+ ExFreePoolWithTag(Data, 'MmPt');
+}
+
+static
+RTL_GENERIC_COMPARE_RESULTS
+NTAPI
+MiSectionPageTableCompare(PRTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB)
+{
+ PLARGE_INTEGER A = PtrA, B = PtrB;
+ BOOLEAN Result = (A->QuadPart < B->QuadPart) ? GenericLessThan :
+ (A->QuadPart == B->QuadPart) ? GenericEqual : GenericGreaterThan;
+
+ DPRINT
+ ("Compare: %08x%08x vs %08x%08x => %s\n",
+ A->u.HighPart, A->u.LowPart,
+ B->u.HighPart, B->u.LowPart,
+ Result == GenericLessThan ? "GenericLessThan" :
+ Result == GenericGreaterThan ? "GenericGreaterThan" :
+ "GenericEqual");
+
+ return Result;
+}
+
+static
+PCACHE_SECTION_PAGE_TABLE
+NTAPI
+MiSectionPageTableGet
+(PRTL_GENERIC_TABLE Table,
+ PLARGE_INTEGER FileOffset)
+{
+ LARGE_INTEGER SearchFileOffset;
+ PCACHE_SECTION_PAGE_TABLE PageTable;
+ SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
+ PageTable = RtlLookupElementGenericTable(Table, &SearchFileOffset);
+ DPRINT
+ ("MiSectionPageTableGet(%08x,%08x%08x)\n",
+ Table,
+ FileOffset->HighPart,
+ FileOffset->LowPart);
+ return PageTable;
+}
+
+static
+PCACHE_SECTION_PAGE_TABLE
+NTAPI
+MiSectionPageTableGetOrAllocate
+(PRTL_GENERIC_TABLE Table,
+ PLARGE_INTEGER FileOffset)
+{
+ LARGE_INTEGER SearchFileOffset;
+ PCACHE_SECTION_PAGE_TABLE PageTableSlice =
+ MiSectionPageTableGet(Table, FileOffset);
+ if (!PageTableSlice)
+ {
+ CACHE_SECTION_PAGE_TABLE SectionZeroPageTable = { };
+ SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
+ SectionZeroPageTable.FileOffset = SearchFileOffset;
+ SectionZeroPageTable.Refcount = 1;
+ PageTableSlice = RtlInsertElementGenericTable
+ (Table, &SectionZeroPageTable, sizeof(SectionZeroPageTable), NULL);
+ DPRINT
+ ("Allocate page table %x (%08x%08x)\n",
+ PageTableSlice,
+ PageTableSlice->FileOffset.u.HighPart,
+ PageTableSlice->FileOffset.u.LowPart);
+ if (!PageTableSlice) return NULL;
+ }
+ return PageTableSlice;
+}
+
+VOID
+NTAPI
+MiInitializeSectionPageTable(PMM_CACHE_SECTION_SEGMENT Segment)
+{
+ RtlInitializeGenericTable
+ (&Segment->PageTable,
+ MiSectionPageTableCompare,
+ MiSectionPageTableAllocate,
+ MiSectionPageTableFree,
+ NULL);
+ DPRINT("MiInitializeSectionPageTable(%p)\n", &Segment->PageTable);
+}
+
+NTSTATUS
+NTAPI
+_MiSetPageEntryCacheSectionSegment
+(PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER Offset,
+ ULONG Entry,
+ const char *file,
+ int line)
+{
+ ULONG PageIndex, OldEntry;
+ PCACHE_SECTION_PAGE_TABLE PageTable;
+ PageTable =
+ MiSectionPageTableGetOrAllocate(&Segment->PageTable, Offset);
+ if (!PageTable) return STATUS_NO_MEMORY;
+ ASSERT(MiSectionPageTableGet(&Segment->PageTable, Offset));
+ PageTable->Segment = Segment;
+ PageIndex =
+ (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
+ OldEntry = PageTable->PageEntries[PageIndex];
+ if (OldEntry && !IS_SWAP_FROM_SSE(OldEntry)) {
+ MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry));
+ }
+ if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
+ MmSetSectionAssociation(PFN_FROM_SSE(Entry), Segment, Offset);
+ }
+ PageTable->PageEntries[PageIndex] = Entry;
+ DPRINT
+ ("MiSetPageEntrySectionSegment(%p,%08x%08x,%x) %s:%d\n",
+ Segment, Offset->u.HighPart, Offset->u.LowPart, Entry, file, line);
+ return STATUS_SUCCESS;
+}
+
+ULONG
+NTAPI
+_MiGetPageEntryCacheSectionSegment
+(PMM_CACHE_SECTION_SEGMENT Segment,
+ PLARGE_INTEGER Offset,
+ const char *file,
+ int line)
+{
+ LARGE_INTEGER FileOffset;
+ ULONG PageIndex, Result;
+ PCACHE_SECTION_PAGE_TABLE PageTable;
+
+ FileOffset.QuadPart =
+ ROUND_DOWN(Offset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
+ PageTable = MiSectionPageTableGet(&Segment->PageTable, &FileOffset);
+ if (!PageTable) return 0;
+ PageIndex =
+ (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
+ Result = PageTable->PageEntries[PageIndex];
+#if 0
+ DPRINTC
+ ("MiGetPageEntrySectionSegment(%p,%08x%08x) => %x %s:%d\n",
+ Segment,
+ FileOffset.u.HighPart,
+ FileOffset.u.LowPart + PageIndex * PAGE_SIZE,
+ Result,
+ file, line);
+#endif
+ return Result;
+}
+
+VOID
+NTAPI
+MiFreePageTablesSectionSegment
+(PMM_CACHE_SECTION_SEGMENT Segment, FREE_SECTION_PAGE_FUN FreePage)
+{
+ PCACHE_SECTION_PAGE_TABLE Element;
+ DPRINT("MiFreePageTablesSectionSegment(%p)\n", &Segment->PageTable);
+ while ((Element = RtlGetElementGenericTable(&Segment->PageTable, 0))) {
+ DPRINT
+ ("Delete table for %x -> %08x%08x\n",
+ Segment,
+ Element->FileOffset.u.HighPart,
+ Element->FileOffset.u.LowPart);
+ if (FreePage)
+ {
+ int i;
+ for (i = 0; i < ENTRIES_PER_ELEMENT; i++)
+ {
+ ULONG Entry;
+ LARGE_INTEGER Offset;
+ Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE;
+ Entry = Element->PageEntries[i];
+ if (Entry && !IS_SWAP_FROM_SSE(Entry))
+ {
+ DPRINTC("Freeing page %x:%x @ %x\n", Segment, Entry, Offset.LowPart);
+ FreePage(Segment, &Offset);
+ }
+ }
+ }
+ DPRINT("Remove memory\n");
+ RtlDeleteElementGenericTable(&Segment->PageTable, Element);
+ }
+ DPRINT("Done\n");
+}
+
+PMM_CACHE_SECTION_SEGMENT
+NTAPI
+MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset)
+{
+ ULONG RawOffset;
+ PMM_CACHE_SECTION_SEGMENT Segment = NULL;
+ PCACHE_SECTION_PAGE_TABLE PageTable;
+
+ PageTable = (PCACHE_SECTION_PAGE_TABLE)MmGetSegmentRmap(Page, &RawOffset);
+ if (PageTable)
+ {
+ Segment = PageTable->Segment;
+ Offset->QuadPart = PageTable->FileOffset.QuadPart + (RawOffset << PAGE_SHIFT);
+ }
+
+ return(Segment);
+}
+
+NTSTATUS
+NTAPI
+MmSetSectionAssociation(PFN_NUMBER Page, PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset)
+{
+ PCACHE_SECTION_PAGE_TABLE PageTable;
+ ULONG ActualOffset;
+ PageTable = MiSectionPageTableGet(&Segment->PageTable, Offset);
+ ASSERT(PageTable);
+ ActualOffset = (ULONG)(Offset->QuadPart - PageTable->FileOffset.QuadPart);
+ MmInsertRmap(Page, (PEPROCESS)PageTable, (PVOID)(RMAP_SEGMENT_MASK | (ActualOffset >> PAGE_SHIFT)));
+ return STATUS_SUCCESS;
+}
diff --git a/reactos/ntoskrnl/cache/section/swapout.c b/reactos/ntoskrnl/cache/section/swapout.c
new file mode 100644
index 00000000000..685104e3d64
--- /dev/null
+++ b/reactos/ntoskrnl/cache/section/swapout.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/mm/section/fault.c
+ * PURPOSE: Consolidate fault handlers for sections
+ *
+ * PROGRAMMERS: Arty
+ * Rex Jolliff
+ * David Welch
+ * Eric Kohl
+ * Emanuele Aliberti
+ * Eugene Ingerman
+ * Casper Hornstrup
+ * KJK::Hyperion
+ * Guido de Jong
+ * Ge van Geldorp
+ * Royce Mitchell III
+ * Filip Navara
+ * Aleksey Bragin
+ * Jason Filby
+ * Thomas Weidenmueller
+ * Gunnar Andre' Dalsnes
+ * Mike Nordell
+ * Alex Ionescu
+ * Gregor Anich
+ * Steven Edwards
+ * Herve Poussineau
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include
+#include "newmm.h"
+#define NDEBUG
+#include
+
+#define DPRINTC DPRINT
+
+extern KEVENT MmWaitPageEvent;
+extern FAST_MUTEX RmapListLock;
+
+FAST_MUTEX GlobalPageOperation;
+
+PFN_NUMBER
+NTAPI
+MmWithdrawSectionPage
+(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, BOOLEAN *Dirty)
+{
+ ULONG Entry;
+
+ DPRINT("MmWithdrawSectionPage(%x,%08x%08x,%x)\n", Segment, FileOffset->HighPart, FileOffset->LowPart, Dirty);
+
+ MmLockCacheSectionSegment(Segment);
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, FileOffset);
+
+ *Dirty = !!IS_DIRTY_SSE(Entry);
+
+ DPRINT("Withdraw %x (%x) of %wZ\n", FileOffset->LowPart, Entry, Segment->FileObject ? &Segment->FileObject->FileName : NULL);
+
+ if (!Entry)
+ {
+ DPRINT("Stoeled!\n");
+ MmUnlockCacheSectionSegment(Segment);
+ return 0;
+ }
+ else if (MM_IS_WAIT_PTE(Entry))
+ {
+ DPRINT("WAIT\n");
+ MmUnlockCacheSectionSegment(Segment);
+ return MM_WAIT_ENTRY;
+ }
+ else if (Entry && !IS_SWAP_FROM_SSE(Entry))
+ {
+ DPRINT("Page %x\n", PFN_FROM_SSE(Entry));
+ *Dirty |= (Entry & 2);
+ MiSetPageEntryCacheSectionSegment(Segment, FileOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
+ MmUnlockCacheSectionSegment(Segment);
+ return PFN_FROM_SSE(Entry);
+ }
+ else
+ {
+ DPRINT1("SWAP ENTRY?! (%x:%08x%08x)\n", Segment, FileOffset->HighPart, FileOffset->LowPart);
+ ASSERT(FALSE);
+ MmUnlockCacheSectionSegment(Segment);
+ return 0;
+ }
+}
+
+NTSTATUS
+NTAPI
+MmFinalizeSectionPageOut
+(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, PFN_NUMBER Page,
+ BOOLEAN Dirty)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOLEAN WriteZero = FALSE, WritePage = FALSE;
+ SWAPENTRY Swap = MmGetSavedSwapEntryPage(Page);
+
+ MmLockCacheSectionSegment(Segment);
+ (void)InterlockedIncrementUL(&Segment->ReferenceCount);
+
+ if (Dirty)
+ {
+ DPRINT("Finalize (dirty) Segment %x Page %x\n", Segment, Page);
+ DPRINT("Segment->FileObject %x\n", Segment->FileObject);
+ DPRINT("Segment->Flags %x\n", Segment->Flags);
+
+ WriteZero = TRUE;
+ WritePage = TRUE;
+ }
+ else
+ {
+ WriteZero = TRUE;
+ }
+
+ DPRINT("Status %x\n", Status);
+
+ MmUnlockCacheSectionSegment(Segment);
+
+ if (WritePage)
+ {
+ DPRINT("MiWriteBackPage(Segment %x FileObject %x Offset %x)\n", Segment, Segment->FileObject, FileOffset->LowPart);
+ Status = MiWriteBackPage(Segment->FileObject, FileOffset, PAGE_SIZE, Page);
+ }
+
+ MmLockCacheSectionSegment(Segment);
+
+ if (WriteZero && NT_SUCCESS(Status))
+ {
+ DPRINT("Setting page entry in segment %x:%x to swap %x\n", Segment, FileOffset->LowPart, Swap);
+ MiSetPageEntryCacheSectionSegment(Segment, FileOffset, Swap ? MAKE_SWAP_SSE(Swap) : 0);
+ }
+ else
+ {
+ DPRINT("Setting page entry in segment %x:%x to page %x\n", Segment, FileOffset->LowPart, Page);
+ MiSetPageEntryCacheSectionSegment
+ (Segment, FileOffset, Page ? (Dirty ? DIRTY_SSE(MAKE_PFN_SSE(Page)) : MAKE_PFN_SSE(Page)) : 0);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("Removing page %x for real\n", Page);
+ MmSetSavedSwapEntryPage(Page, 0);
+ // Note: the other one is held by MmTrimUserMemory
+ if (MmGetReferenceCountPage(Page) != 2) {
+ DPRINT1("ALERT: Page %x about to be evicted with ref count %d\n", Page, MmGetReferenceCountPage(Page));
+ }
+ MmDereferencePage(Page);
+ }
+
+ MmUnlockCacheSectionSegment(Segment);
+
+ if (InterlockedDecrementUL(&Segment->ReferenceCount) == 0)
+ {
+ MmFinalizeSegment(Segment);
+ }
+
+ /* Note: Writing may evict the segment... Nothing is guaranteed from here down */
+ MiSetPageEvent(Segment, FileOffset->LowPart);
+
+ DPRINT("Status %x\n", Status);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MmPageOutCacheSection
+(PMMSUPPORT AddressSpace,
+ MEMORY_AREA* MemoryArea,
+ PVOID Address,
+ PMM_REQUIRED_RESOURCES Required)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Entry;
+ BOOLEAN Dirty = FALSE;
+ PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+ LARGE_INTEGER TotalOffset;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+ PVOID PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
+
+ TotalOffset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress +
+ MemoryArea->Data.CacheData.ViewOffset.QuadPart;
+
+ Segment = MemoryArea->Data.CacheData.Segment;
+
+ MmLockCacheSectionSegment(Segment);
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+
+ Dirty = MmIsDirtyPageRmap(Required->Page[0]);
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, &TotalOffset);
+
+ if (Dirty)
+ {
+ PFN_NUMBER OurPage;
+ MiSetPageEntryCacheSectionSegment(Segment, &TotalOffset, DIRTY_SSE(Entry));
+ MmDeleteRmap(Required->Page[0], Process, Address);
+ MmDeleteVirtualMapping(Process, Address, FALSE, &Dirty, &OurPage);
+ ASSERT(OurPage == Required->Page[0]);
+ } else {
+ /* Just unmap if the page wasn't dirty */
+ PFN_NUMBER OurPage;
+ MmDeleteRmap(Required->Page[0], Process, Address);
+ MmDeleteVirtualMapping(Process, Address, FALSE, &Dirty, &OurPage);
+ DPRINT("OurPage %x ThePage %x\n", OurPage, Required->Page[0]);
+ ASSERT(OurPage == Required->Page[0]);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ MmDereferencePage(Required->Page[0]);
+ }
+
+ MmUnlockCacheSectionSegment(Segment);
+ MiSetPageEvent(Process, Address);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+MmpPageOutPhysicalAddress(PFN_NUMBER Page)
+{
+ BOOLEAN ProcRef = FALSE;
+ PFN_NUMBER SectionPage = 0;
+ PMM_RMAP_ENTRY entry;
+ PMM_CACHE_SECTION_SEGMENT Segment = NULL;
+ LARGE_INTEGER FileOffset;
+ PMEMORY_AREA MemoryArea;
+ PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
+ BOOLEAN Dirty = FALSE;
+ PVOID Address = NULL;
+ PEPROCESS Process = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+ MM_REQUIRED_RESOURCES Resources = { 0 };
+
+ DPRINTC("Page out %x (ref ct %x)\n", Page, MmGetReferenceCountPage(Page));
+
+ ExAcquireFastMutex(&GlobalPageOperation);
+ if ((Segment = MmGetSectionAssociation(Page, &FileOffset)))
+ {
+ DPRINT1("Withdrawing page (%x) %x:%x\n", Page, Segment, FileOffset.LowPart);
+ SectionPage = MmWithdrawSectionPage(Segment, &FileOffset, &Dirty);
+ DPRINTC("SectionPage %x\n", SectionPage);
+
+ if (SectionPage == MM_WAIT_ENTRY || SectionPage == 0)
+ {
+ DPRINT1("In progress page out %x\n", SectionPage);
+ ExReleaseFastMutex(&GlobalPageOperation);
+ return STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ ASSERT(SectionPage == Page);
+ }
+ Resources.State = Dirty ? 1 : 0;
+ }
+ else
+ {
+ DPRINT("No segment association for %x\n", Page);
+ }
+
+
+ Dirty = MmIsDirtyPageRmap(Page);
+
+ DPRINTC("Trying to unmap all instances of %x\n", Page);
+ ExAcquireFastMutex(&RmapListLock);
+ entry = MmGetRmapListHeadPage(Page);
+
+ // Entry and Segment might be null here in the case that the page
+ // is new and is in the process of being swapped in
+ if (!entry && !Segment)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ DPRINT1("Page %x is in transit\n", Page);
+ ExReleaseFastMutex(&RmapListLock);
+ goto bail;
+ }
+
+ while (entry != NULL && NT_SUCCESS(Status))
+ {
+ Process = entry->Process;
+ Address = entry->Address;
+
+ DPRINTC("Process %x Address %x Page %x\n", Process, Address, Page);
+
+ if (RMAP_IS_SEGMENT(Address)) {
+ entry = entry->Next;
+ continue;
+ }
+
+ if (Process && Address < MmSystemRangeStart)
+ {
+ // Make sure we don't try to page out part of an exiting process
+ if (PspIsProcessExiting(Process))
+ {
+ DPRINT("bail\n");
+ ExReleaseFastMutex(&RmapListLock);
+ goto bail;
+ }
+ Status = ObReferenceObject(Process);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("bail\n");
+ ExReleaseFastMutex(&RmapListLock);
+ goto bail;
+ }
+ ProcRef = TRUE;
+ AddressSpace = &Process->Vm;
+ }
+ else
+ {
+ AddressSpace = MmGetKernelAddressSpace();
+ }
+ ExReleaseFastMutex(&RmapListLock);
+
+ RtlZeroMemory(&Resources, sizeof(Resources));
+
+ if ((((ULONG_PTR)Address) & 0xFFF) != 0)
+ {
+ KeBugCheck(MEMORY_MANAGEMENT);
+ }
+
+ if (!MmTryToLockAddressSpace(AddressSpace))
+ {
+ DPRINT1("Could not lock address space for process %x\n", MmGetAddressSpaceOwner(AddressSpace));
+ Status = STATUS_UNSUCCESSFUL;
+ goto bail;
+ }
+
+ do
+ {
+ MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
+ if (MemoryArea == NULL ||
+ MemoryArea->DeleteInProgress)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ MmUnlockAddressSpace(AddressSpace);
+ DPRINTC("bail\n");
+ goto bail;
+ }
+
+ DPRINTC
+ ("Type %x (%x -> %x)\n",
+ MemoryArea->Type,
+ MemoryArea->StartingAddress,
+ MemoryArea->EndingAddress);
+
+ Resources.DoAcquisition = NULL;
+
+ Resources.Page[0] = Page;
+
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+
+ DPRINT("%x:%x, page %x %x\n", Process, Address, Page, Resources.Page[0]);
+ Status = MmPageOutCacheSection
+ (AddressSpace, MemoryArea, Address, &Resources);
+ DPRINT("%x\n", Status);
+
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+
+ MmUnlockAddressSpace(AddressSpace);
+
+ if (Status == STATUS_SUCCESS + 1)
+ {
+ // Wait page ... the other guy has it, so we'll just fail for now
+ DPRINTC("Wait entry ... can't continue\n");
+ Status = STATUS_UNSUCCESSFUL;
+ goto bail;
+ }
+ else if (Status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ DPRINTC("DoAcquisition %x\n", Resources.DoAcquisition);
+ Status = Resources.DoAcquisition(AddressSpace, MemoryArea, &Resources);
+ DPRINTC("Status %x\n", Status);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("bail\n");
+ goto bail;
+ }
+ else Status = STATUS_MM_RESTART_OPERATION;
+ }
+
+ MmLockAddressSpace(AddressSpace);
+ }
+ while (Status == STATUS_MM_RESTART_OPERATION);
+ Dirty |= Resources.State & 1; // Accumulate dirty
+
+ MmUnlockAddressSpace(AddressSpace);
+
+ if (ProcRef)
+ {
+ ObDereferenceObject(Process);
+ ProcRef = FALSE;
+ }
+
+ ExAcquireFastMutex(&RmapListLock);
+ ASSERT(!MM_IS_WAIT_PTE(MmGetPfnForProcess(Process, Address)));
+ entry = MmGetRmapListHeadPage(Page);
+
+ DPRINTC("Entry %x\n", entry);
+ }
+
+ ExReleaseFastMutex(&RmapListLock);
+
+bail:
+ DPRINTC("BAIL %x\n", Status);
+
+ if (Segment)
+ {
+ DPRINTC("About to finalize section page %x (%x:%x) Status %x %s\n", Page, Segment, FileOffset.LowPart, Status, Dirty ? "dirty" : "clean");
+
+ if (!NT_SUCCESS(Status) ||
+ !NT_SUCCESS
+ (Status = MmFinalizeSectionPageOut
+ (Segment, &FileOffset, Page, Dirty)))
+ {
+ DPRINTC
+ ("Failed to page out %x, replacing %x at %x in segment %x\n",
+ SectionPage, FileOffset.LowPart, Segment);
+ MmLockCacheSectionSegment(Segment);
+ MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, Dirty ? MAKE_PFN_SSE(Page) : DIRTY_SSE(MAKE_PFN_SSE(Page)));
+ MmUnlockCacheSectionSegment(Segment);
+ }
+
+ // Alas, we had the last reference
+ ULONG RefCount;
+ if ((RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
+ MmFinalizeSegment(Segment);
+ }
+
+ if (ProcRef)
+ {
+ DPRINTC("Dereferencing process...\n");
+ ObDereferenceObject(Process);
+ }
+
+ ExReleaseFastMutex(&GlobalPageOperation);
+ DPRINTC("%s %x %x\n", NT_SUCCESS(Status) ? "Evicted" : "Spared", Page, Status);
+ return NT_SUCCESS(Status) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
+ULONG
+NTAPI
+MiCacheEvictPages(PVOID BaseAddress, ULONG Target)
+{
+ ULONG i, Entry, Result = 0;
+ NTSTATUS Status;
+ PFN_NUMBER Page;
+ PMEMORY_AREA MemoryArea;
+ LARGE_INTEGER Offset;
+ PMM_CACHE_SECTION_SEGMENT Segment;
+
+ MmLockAddressSpace(MmGetKernelAddressSpace());
+ MemoryArea = MmLocateMemoryAreaByAddress
+ (MmGetKernelAddressSpace(),
+ BaseAddress);
+
+ ASSERT(MemoryArea);
+ ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE);
+
+ Segment = MemoryArea->Data.CacheData.Segment;
+
+ ASSERT(Segment);
+
+ MmLockCacheSectionSegment(Segment);
+
+ for (i = 0;
+ i < Segment->Length.QuadPart -
+ MemoryArea->Data.CacheData.ViewOffset.QuadPart &&
+ Result < Target;
+ i += PAGE_SIZE) {
+ Offset.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart + i;
+ Entry = MiGetPageEntryCacheSectionSegment(Segment, &Offset);
+ if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
+ Page = PFN_FROM_SSE(Entry);
+ MmReferencePage(Page);
+ MmUnlockCacheSectionSegment(Segment);
+ MmUnlockAddressSpace(MmGetKernelAddressSpace());
+ Status = MmpPageOutPhysicalAddress(Page);
+ if (NT_SUCCESS(Status))
+ Result++;
+ MmLockCacheSectionSegment(Segment);
+ MmLockAddressSpace(MmGetKernelAddressSpace());
+ MmReleasePageMemoryConsumer(MC_CACHE, Page);
+ }
+ }
+
+ MmUnlockCacheSectionSegment(Segment);
+ MmUnlockAddressSpace(MmGetKernelAddressSpace());
+
+ return Result;
+}
+
diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h
index 25360af7416..9da455b0779 100644
--- a/reactos/ntoskrnl/include/internal/mm.h
+++ b/reactos/ntoskrnl/include/internal/mm.h
@@ -248,6 +248,8 @@ typedef struct _ROS_SECTION_OBJECT
};
} ROS_SECTION_OBJECT, *PROS_SECTION_OBJECT;
+struct _MM_CACHE_SECTION_SEGMENT;
+
typedef struct _MEMORY_AREA
{
PVOID StartingAddress;
@@ -270,6 +272,11 @@ typedef struct _MEMORY_AREA
PMM_SECTION_SEGMENT Segment;
LIST_ENTRY RegionListHead;
} SectionData;
+ struct
+ {
+ LARGE_INTEGER ViewOffset;
+ struct _MM_CACHE_SECTION_SEGMENT *Segment;
+ } CacheData;
struct
{
LIST_ENTRY RegionListHead;
@@ -1286,6 +1293,14 @@ VOID
NTAPI
MmRawDeleteVirtualMapping(PVOID Address);
+
+VOID
+NTAPI
+MmGetPageFileMapping(
+ struct _EPROCESS *Process,
+ PVOID Address,
+ SWAPENTRY* SwapEntry);
+
VOID
NTAPI
MmDeletePageFileMapping(
diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h
index 1d55e3068ff..bf18cf818b3 100644
--- a/reactos/ntoskrnl/include/internal/ps.h
+++ b/reactos/ntoskrnl/include/internal/ps.h
@@ -399,6 +399,10 @@ PsChargeProcessPageFileQuota(
IN SIZE_T Amount
);
+BOOLEAN
+NTAPI
+PspIsProcessExiting(IN PEPROCESS Process);
+
//
// Global data inside the Process Manager
//
diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c
index e096fcf3f56..f3e43d9fed8 100644
--- a/reactos/ntoskrnl/mm/i386/page.c
+++ b/reactos/ntoskrnl/mm/i386/page.c
@@ -465,6 +465,18 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
}
}
+VOID
+NTAPI
+MmGetPageFileMapping(PEPROCESS Process, PVOID Address,
+ SWAPENTRY* SwapEntry)
+/*
+ * FUNCTION: Get a page file mapping
+ */
+{
+ ULONG Entry = MmGetPageEntryForProcess(Process, Address);
+ *SwapEntry = Entry >> 1;
+}
+
VOID
NTAPI
MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
diff --git a/reactos/ntoskrnl/mm/mmfault.c b/reactos/ntoskrnl/mm/mmfault.c
index bf8b2e014c7..9a3ecf9f0ef 100644
--- a/reactos/ntoskrnl/mm/mmfault.c
+++ b/reactos/ntoskrnl/mm/mmfault.c
@@ -9,6 +9,9 @@
/* INCLUDES *******************************************************************/
#include
+#ifdef NEWCC
+#include "../cache/section/newmm.h"
+#endif
#define NDEBUG
#include
@@ -85,6 +88,18 @@ MmpAccessFault(KPROCESSOR_MODE Mode,
Status = STATUS_ACCESS_VIOLATION;
break;
+#ifdef NEWCC
+ case MEMORY_AREA_CACHE:
+ // This code locks for itself to keep from having to break a lock
+ // passed in.
+ if (!FromMdl)
+ MmUnlockAddressSpace(AddressSpace);
+ Status = MmAccessFaultCacheSection(Mode, Address, Locked);
+ if (!FromMdl)
+ MmLockAddressSpace(AddressSpace);
+ break;
+#endif
+
default:
Status = STATUS_ACCESS_VIOLATION;
break;
@@ -175,6 +190,18 @@ MmNotPresentFault(KPROCESSOR_MODE Mode,
Locked);
break;
+#ifdef NEWCC
+ case MEMORY_AREA_CACHE:
+ // This code locks for itself to keep from having to break a lock
+ // passed in.
+ if (!FromMdl)
+ MmUnlockAddressSpace(AddressSpace);
+ Status = MmNotPresentFaultCacheSection(Mode, Address, Locked);
+ if (!FromMdl)
+ MmLockAddressSpace(AddressSpace);
+ break;
+#endif
+
default:
Status = STATUS_ACCESS_VIOLATION;
break;
diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c
index df2140c9cc7..55233979f65 100644
--- a/reactos/ntoskrnl/mm/mminit.c
+++ b/reactos/ntoskrnl/mm/mminit.c
@@ -302,7 +302,11 @@ MmMpwThreadMain(PVOID Ignored)
PagesWritten = 0;
+#ifndef NEWCC
+ // XXX arty -- we flush when evicting pages or destorying cache
+ // sections.
CcRosFlushDirtyPages(128, &PagesWritten);
+#endif
}
}
diff --git a/reactos/ntoskrnl/mm/rmap.c b/reactos/ntoskrnl/mm/rmap.c
index aa2f96ee3b4..c7bd744f25f 100644
--- a/reactos/ntoskrnl/mm/rmap.c
+++ b/reactos/ntoskrnl/mm/rmap.c
@@ -10,6 +10,7 @@
/* INCLUDES *****************************************************************/
#include
+#include "../cache/section/newmm.h"
#define NDEBUG
#include
@@ -21,8 +22,8 @@
/* GLOBALS ******************************************************************/
-static FAST_MUTEX RmapListLock;
static NPAGED_LOOKASIDE_LIST RmapLookasideList;
+FAST_MUTEX RmapListLock;
/* FUNCTIONS ****************************************************************/
@@ -55,6 +56,8 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page)
ULONG Offset;
NTSTATUS Status = STATUS_SUCCESS;
+ ASSERT(FALSE);
+
ExAcquireFastMutex(&RmapListLock);
entry = MmGetRmapListHeadPage(Page);
if (entry == NULL)
@@ -65,6 +68,7 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page)
Process = entry->Process;
Address = entry->Address;
+
if ((((ULONG_PTR)Address) & 0xFFF) != 0)
{
KeBugCheck(MEMORY_MANAGEMENT);
@@ -193,8 +197,9 @@ MmSetCleanAllRmaps(PFN_NUMBER Page)
}
while (current_entry != NULL)
{
- MmSetCleanPage(current_entry->Process, current_entry->Address);
- current_entry = current_entry->Next;
+ if (!RMAP_IS_SEGMENT(current_entry->Address))
+ MmSetCleanPage(current_entry->Process, current_entry->Address);
+ current_entry = current_entry->Next;
}
ExReleaseFastMutex(&RmapListLock);
}
@@ -214,7 +219,8 @@ MmSetDirtyAllRmaps(PFN_NUMBER Page)
}
while (current_entry != NULL)
{
- MmSetDirtyPage(current_entry->Process, current_entry->Address);
+ if (!RMAP_IS_SEGMENT(current_entry->Address))
+ MmSetDirtyPage(current_entry->Process, current_entry->Address);
current_entry = current_entry->Next;
}
ExReleaseFastMutex(&RmapListLock);
@@ -235,7 +241,8 @@ MmIsDirtyPageRmap(PFN_NUMBER Page)
}
while (current_entry != NULL)
{
- if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
+ if (!RMAP_IS_SEGMENT(current_entry->Address) &&
+ MmIsDirtyPage(current_entry->Process, current_entry->Address))
{
ExReleaseFastMutex(&RmapListLock);
return(TRUE);
@@ -255,7 +262,8 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
PMM_RMAP_ENTRY new_entry;
ULONG PrevSize;
- Address = (PVOID)PAGE_ROUND_DOWN(Address);
+ if (!RMAP_IS_SEGMENT(Address))
+ Address = (PVOID)PAGE_ROUND_DOWN(Address);
new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
if (new_entry == NULL)
@@ -272,7 +280,8 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
#endif
#endif
- if (MmGetPfnForProcess(Process, Address) != Page)
+ if (!RMAP_IS_SEGMENT(Address) &&
+ MmGetPfnForProcess(Process, Address) != Page)
{
DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
"address 0x%.8X\n", Process->UniqueProcessId, Address,
@@ -302,17 +311,21 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
#endif
MmSetRmapListHeadPage(Page, new_entry);
ExReleaseFastMutex(&RmapListLock);
- if (Process == NULL)
+
+ if (!RMAP_IS_SEGMENT(Address))
{
- Process = PsInitialSystemProcess;
- }
- if (Process)
- {
- PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
- if (PrevSize >= Process->Vm.PeakWorkingSetSize)
- {
- Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
- }
+ if (Process == NULL)
+ {
+ Process = PsInitialSystemProcess;
+ }
+ if (Process)
+ {
+ PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
+ if (PrevSize >= Process->Vm.PeakWorkingSetSize)
+ {
+ Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
+ }
+ }
}
}
@@ -339,21 +352,28 @@ MmDeleteAllRmaps(PFN_NUMBER Page, PVOID Context,
{
previous_entry = current_entry;
current_entry = current_entry->Next;
- if (DeleteMapping)
- {
- DeleteMapping(Context, previous_entry->Process,
- previous_entry->Address);
- }
- Process = previous_entry->Process;
- ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
- if (Process == NULL)
- {
- Process = PsInitialSystemProcess;
- }
- if (Process)
- {
- (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
- }
+ if (!RMAP_IS_SEGMENT(current_entry->Address))
+ {
+ if (DeleteMapping)
+ {
+ DeleteMapping(Context, previous_entry->Process,
+ previous_entry->Address);
+ }
+ Process = previous_entry->Process;
+ ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
+ if (Process == NULL)
+ {
+ Process = PsInitialSystemProcess;
+ }
+ if (Process)
+ {
+ (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
+ }
+ }
+ else
+ {
+ ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
+ }
}
}
@@ -383,14 +403,16 @@ MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process,
}
ExReleaseFastMutex(&RmapListLock);
ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
- if (Process == NULL)
- {
- Process = PsInitialSystemProcess;
- }
- if (Process)
- {
- (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
- }
+ if (!RMAP_IS_SEGMENT(Address)) {
+ if (Process == NULL)
+ {
+ Process = PsInitialSystemProcess;
+ }
+ if (Process)
+ {
+ (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
+ }
+ }
return;
}
previous_entry = current_entry;
@@ -398,3 +420,61 @@ MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process,
}
KeBugCheck(MEMORY_MANAGEMENT);
}
+
+PVOID
+NTAPI
+MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
+{
+ PCACHE_SECTION_PAGE_TABLE Result = NULL;
+ PMM_RMAP_ENTRY current_entry, previous_entry;
+
+ ExAcquireFastMutex(&RmapListLock);
+ previous_entry = NULL;
+ current_entry = MmGetRmapListHeadPage(Page);
+ while (current_entry != NULL)
+ {
+ if (RMAP_IS_SEGMENT(current_entry->Address))
+ {
+ Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
+ *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
+ InterlockedIncrementUL(&Result->Segment->ReferenceCount);
+ ExReleaseFastMutex(&RmapListLock);
+ return Result;
+ }
+ previous_entry = current_entry;
+ current_entry = current_entry->Next;
+ }
+ ExReleaseFastMutex(&RmapListLock);
+ return NULL;
+}
+
+VOID
+NTAPI
+MmDeleteSectionAssociation(PFN_NUMBER Page)
+{
+ PMM_RMAP_ENTRY current_entry, previous_entry;
+
+ ExAcquireFastMutex(&RmapListLock);
+ previous_entry = NULL;
+ current_entry = MmGetRmapListHeadPage(Page);
+ while (current_entry != NULL)
+ {
+ if (RMAP_IS_SEGMENT(current_entry->Address))
+ {
+ if (previous_entry == NULL)
+ {
+ MmSetRmapListHeadPage(Page, current_entry->Next);
+ }
+ else
+ {
+ previous_entry->Next = current_entry->Next;
+ }
+ ExReleaseFastMutex(&RmapListLock);
+ ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
+ return;
+ }
+ previous_entry = current_entry;
+ current_entry = current_entry->Next;
+ }
+ ExReleaseFastMutex(&RmapListLock);
+}
diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c
index 5dad201e343..6e226d4b84c 100644
--- a/reactos/ntoskrnl/mm/section.c
+++ b/reactos/ntoskrnl/mm/section.c
@@ -45,6 +45,9 @@
/* INCLUDES *****************************************************************/
#include
+#ifdef NEWCC
+#include "../cache/section/newmm.h"
+#endif
#define NDEBUG
#include
#include
@@ -745,7 +748,7 @@ MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
* ARGUMENTS: PFILE_OBJECT to wait for.
* RETURNS: Status of the wait.
*/
-static NTSTATUS
+NTSTATUS
MmspWaitForFileLock(PFILE_OBJECT File)
{
return STATUS_SUCCESS;
@@ -979,7 +982,11 @@ MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
NTSTATUS Status;
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
IsDirectMapped = TRUE;
+#ifndef NEWCC
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
+#else
+ Status = STATUS_SUCCESS;
+#endif
if (!NT_SUCCESS(Status))
{
DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
@@ -1057,6 +1064,7 @@ MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
ULONG SegOffset)
{
+#ifndef NEWCC
if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
{
PBCB Bcb;
@@ -1069,6 +1077,7 @@ BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
return TRUE;
}
}
+#endif
return FALSE;
}
@@ -1091,6 +1100,7 @@ MiCopyFromUserPage(PFN_NUMBER DestPage, PVOID SourceAddress)
return(STATUS_SUCCESS);
}
+#ifndef NEWCC
NTSTATUS
NTAPI
MiReadPage(PMEMORY_AREA MemoryArea,
@@ -1267,6 +1277,35 @@ MiReadPage(PMEMORY_AREA MemoryArea,
}
return(STATUS_SUCCESS);
}
+#else
+NTSTATUS
+NTAPI
+MiReadPage(PMEMORY_AREA MemoryArea,
+ ULONG SegOffset,
+ PPFN_NUMBER Page)
+/*
+ * FUNCTION: Read a page for a section backed memory area.
+ * PARAMETERS:
+ * MemoryArea - Memory area to read the page for.
+ * Offset - Offset of the page to read.
+ * Page - Variable that receives a page contains the read data.
+ */
+{
+ MM_REQUIRED_RESOURCES Resources = { };
+
+ Resources.Context = MemoryArea->Data.SectionData.Section->FileObject;
+ Resources.FileOffset.QuadPart = SegOffset +
+ MemoryArea->Data.SectionData.Segment->FileOffset;
+ Resources.Consumer = MC_USER;
+ Resources.Amount = PAGE_SIZE;
+
+ DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT)Resources.Context)->FileName.Buffer, Resources.FileOffset.LowPart, Resources.Amount, Resources.Page[0]);
+
+ NTSTATUS Status = MiReadFilePage(NULL, NULL, &Resources);
+ *Page = Resources.Page[0];
+ return Status;
+}
+#endif
NTSTATUS
NTAPI
@@ -1388,6 +1427,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
if (!MmIsPagePresent(Process, Address))
{
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
+ DPRINT1("Entry %x\n", Entry);
HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
@@ -1587,6 +1627,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
{
DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
}
+
}
else
{
@@ -1624,7 +1665,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
if (Entry != Entry1)
{
DPRINT1("Someone changed ppte entry while we slept\n");
- KeBugCheck(MEMORY_MANAGEMENT);
+ KeBugCheck(MEMORY_MANAGEMENT);
}
/*
@@ -2151,7 +2192,11 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
Address);
KeBugCheck(MEMORY_MANAGEMENT);
}
+#ifndef NEWCC
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
+#else
+ Status = STATUS_SUCCESS;
+#endif
if (!NT_SUCCESS(Status))
{
DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
@@ -2429,7 +2474,9 @@ MmWritePageSectionView(PMMSUPPORT AddressSpace,
if (DirectMapped && !Private)
{
ASSERT(SwapEntry == 0);
+#ifndef NEWCC
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
+#endif
PageOp->Status = STATUS_SUCCESS;
MmspCompleteAndReleasePageOp(PageOp);
return(STATUS_SUCCESS);
@@ -2717,7 +2764,9 @@ MmpDeleteSection(PVOID ObjectBody)
}
if (Section->FileObject != NULL)
{
+#ifndef NEWCC
CcRosDereferenceCache(Section->FileObject);
+#endif
ObDereferenceObject(Section->FileObject);
Section->FileObject = NULL;
}
@@ -3122,7 +3171,9 @@ MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
MmUnlockSectionSegment(Segment);
Section->FileObject = FileObject;
Section->MaximumSize = MaximumSize;
+#ifndef NEWCC
CcRosReferenceCache(FileObject);
+#endif
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
*SectionObject = Section;
return(STATUS_SUCCESS);
@@ -3853,11 +3904,15 @@ MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
Section->SectionPageProtection = SectionPageProtection;
Section->AllocationAttributes = AllocationAttributes;
+#ifndef NEWCC
/*
* Initialized caching for this file object if previously caching
* was initialized for the same on disk file
*/
Status = CcTryToInitializeFileCache(FileObject);
+#else
+ Status = STATUS_SUCCESS;
+#endif
if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
{
@@ -3950,7 +4005,9 @@ MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
Status = STATUS_SUCCESS;
}
Section->FileObject = FileObject;
+#ifndef NEWCC
CcRosReferenceCache(FileObject);
+#endif
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
*SectionObject = Section;
return(Status);
@@ -4062,7 +4119,9 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
{
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
+#ifndef NEWCC
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
+#endif
ASSERT(SwapEntry == 0);
}
}
@@ -4749,7 +4808,9 @@ MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
{
return FALSE;
}
+#ifndef NEWCC
CcRosSetRemoveOnClose(SectionObjectPointer);
+#endif
return TRUE;
case MmFlushForWrite:
break;
diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild
index 74fdf0b4531..6056698c2b2 100644
--- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild
+++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild
@@ -14,6 +14,9 @@
+
+
+
.
include
@@ -130,14 +133,35 @@
timerobj.c
wait.c
-
+
+
cacheman.c
copy.c
fs.c
mdl.c
pin.c
view.c
-
+
+
+
+
+ cachesub.c
+ copysup.c
+ fssup.c
+ lazyrite.c
+ logsup.c
+ mdlsup.c
+ pinsup.c
+
+ data.c
+ fault.c
+ io.c
+ reqtools.c
+ sptab.c
+ swapout.c
+
+
+
diff --git a/reactos/ntoskrnl/po/poshtdwn.c b/reactos/ntoskrnl/po/poshtdwn.c
index dd5113e1bb3..919ffd4eefb 100644
--- a/reactos/ntoskrnl/po/poshtdwn.c
+++ b/reactos/ntoskrnl/po/poshtdwn.c
@@ -9,6 +9,9 @@
/* INCLUDES ******************************************************************/
#include
+#ifdef NEWCC
+#include "../cache/newcc.h"
+#endif
#define NDEBUG
#include
@@ -154,6 +157,10 @@ PopGracefulShutdown(IN PVOID Context)
IoShutdownSystem(1);
CcWaitForCurrentLazyWriterActivity();
+#ifdef NEWCC
+ CcShutdownSystem();
+#endif
+
/* Note that here, we should broadcast the power IRP to devices */
/* In this step, the HAL disables any wake timers */
diff --git a/reactos/ntoskrnl/po/power.c b/reactos/ntoskrnl/po/power.c
index a163b98bc48..cb343125edc 100644
--- a/reactos/ntoskrnl/po/power.c
+++ b/reactos/ntoskrnl/po/power.c
@@ -744,8 +744,10 @@ NtSetSystemPowerState(IN POWER_ACTION SystemAction,
/* Check if we're still in an invalid status */
if (!NT_SUCCESS(Status)) break;
+#ifndef NEWCC
/* Flush dirty cache pages */
CcRosFlushDirtyPages(-1, &Dummy);
+#endif
/* Flush all volumes and the registry */
DPRINT1("Flushing volumes, cache flushed %d pages\n", Dummy);
diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c
index b1ea95fb361..7efbc761ad7 100644
--- a/reactos/ntoskrnl/ps/kill.c
+++ b/reactos/ntoskrnl/ps/kill.c
@@ -1012,6 +1012,13 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
return Status;
}
+BOOLEAN
+NTAPI
+PspIsProcessExiting(IN PEPROCESS Process)
+{
+ return Process->Flags & PSF_PROCESS_EXITING_BIT;
+}
+
VOID
NTAPI
PspExitProcess(IN BOOLEAN LastThread,