1c2c66affSColin Finck /*
2a4274ad5SHermès Bélusca-Maïto * PROJECT: ReactOS Kernel
3a4274ad5SHermès Bélusca-Maïto * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4c2c66affSColin Finck * PURPOSE: Paging file functions
5a4274ad5SHermès Bélusca-Maïto * COPYRIGHT: Copyright 1998-2003 David Welch <welch@mcmail.com>
6a4274ad5SHermès Bélusca-Maïto * Copyright 2010-2018 Pierre Schweitzer <pierre@reactos.org>
7c2c66affSColin Finck */
8c2c66affSColin Finck
9c2c66affSColin Finck /* INCLUDES *****************************************************************/
10c2c66affSColin Finck
11c2c66affSColin Finck #include <ntoskrnl.h>
12c2c66affSColin Finck #define NDEBUG
13c2c66affSColin Finck #include <debug.h>
14c2c66affSColin Finck
15c2c66affSColin Finck /* GLOBALS *******************************************************************/
16c2c66affSColin Finck
17a4274ad5SHermès Bélusca-Maïto /* Minimum pagefile size is 256 pages (1 MB) */
18a4274ad5SHermès Bélusca-Maïto #define MINIMUM_PAGEFILE_SIZE (256ULL * PAGE_SIZE)
19a4274ad5SHermès Bélusca-Maïto
20a4274ad5SHermès Bélusca-Maïto /* Maximum pagefile sizes for different architectures */
21a4274ad5SHermès Bélusca-Maïto #if defined(_M_IX86) && !defined(_X86PAE_)
22a4274ad5SHermès Bélusca-Maïto /* Around 4 GB */
23a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE)
24a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(4ULL * GIGABYTE - 1)
25a4274ad5SHermès Bélusca-Maïto /* PAE uses the same size as x64 */
26a4274ad5SHermès Bélusca-Maïto #elif (defined(_M_IX86) && defined(_X86PAE_)) || defined (_M_AMD64) || defined(_M_ARM64)
27a4274ad5SHermès Bélusca-Maïto /* Around 16 TB */
28a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WIN10)
29a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((4ULL * 1024 * 1024 * 1024 - 2) * PAGE_SIZE)
30a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(16ULL * TERABYTE - PAGE_SIZE - 1)
31a4274ad5SHermès Bélusca-Maïto #else
32a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((4ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE)
33a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(16ULL * TERABYTE - 1)
34a4274ad5SHermès Bélusca-Maïto #endif
35a4274ad5SHermès Bélusca-Maïto #elif defined (_M_IA64)
36a4274ad5SHermès Bélusca-Maïto /* Around 32 TB */
37a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((8ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE)
38a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(32ULL * TERABYTE - 1)
39a4274ad5SHermès Bélusca-Maïto #elif defined(_M_ARM)
40a4274ad5SHermès Bélusca-Maïto /* Around 2 GB */
41a4274ad5SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WIN10)
42a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((512ULL * 1024 - 2) * PAGE_SIZE)
43a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(2ULL * GIGABYTE - PAGE_SIZE - 1)
44a4274ad5SHermès Bélusca-Maïto #elif (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
45a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((512ULL * 1024 - 1) * PAGE_SIZE)
46a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(2ULL * GIGABYTE - 1)
47a4274ad5SHermès Bélusca-Maïto #else
48a4274ad5SHermès Bélusca-Maïto /* Around 4 GB */
49a4274ad5SHermès Bélusca-Maïto #define MAXIMUM_PAGEFILE_SIZE ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE)
50a4274ad5SHermès Bélusca-Maïto // PAGE_ROUND_DOWN(4ULL * GIGABYTE - 1)
51a4274ad5SHermès Bélusca-Maïto #endif
52a4274ad5SHermès Bélusca-Maïto #else
53a4274ad5SHermès Bélusca-Maïto #error Unknown architecture
54a4274ad5SHermès Bélusca-Maïto #endif
55c2c66affSColin Finck
56c2c66affSColin Finck /* List of paging files, both used and free */
573814a822SPierre Schweitzer PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
58c2c66affSColin Finck
59c2c66affSColin Finck /* Lock for examining the list of paging files */
60315867d4SPierre Schweitzer KGUARDED_MUTEX MmPageFileCreationLock;
61c2c66affSColin Finck
62c2c66affSColin Finck /* Number of paging files */
63c2c66affSColin Finck ULONG MmNumberOfPagingFiles;
64c2c66affSColin Finck
65c2c66affSColin Finck /* Number of pages that are available for swapping */
66c2c66affSColin Finck PFN_COUNT MiFreeSwapPages;
67c2c66affSColin Finck
68c2c66affSColin Finck /* Number of pages that have been allocated for swapping */
69c2c66affSColin Finck PFN_COUNT MiUsedSwapPages;
70c2c66affSColin Finck
71c2c66affSColin Finck BOOLEAN MmZeroPageFile;
72c2c66affSColin Finck
73c2c66affSColin Finck /*
74c2c66affSColin Finck * Number of pages that have been reserved for swapping but not yet allocated
75c2c66affSColin Finck */
76c2c66affSColin Finck static PFN_COUNT MiReservedSwapPages;
77c2c66affSColin Finck
78c2c66affSColin Finck /*
79c2c66affSColin Finck * Ratio between reserved and available swap pages, e.g. setting this to five
80c2c66affSColin Finck * forces one swap page to be available for every five swap pages that are
81c2c66affSColin Finck * reserved. Setting this to zero turns off commit checking altogether.
82c2c66affSColin Finck */
83c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_RATIO (1)
84c2c66affSColin Finck
85c2c66affSColin Finck /*
86c2c66affSColin Finck * Number of pages that can be used for potentially swapable memory without
87c2c66affSColin Finck * pagefile space being reserved. The intention is that this allows smss
88c2c66affSColin Finck * to start up and create page files while ordinarily having a commit
89c2c66affSColin Finck * ratio of one.
90c2c66affSColin Finck */
91c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_GRACE (256)
92c2c66affSColin Finck
93c2c66affSColin Finck /*
94c2c66affSColin Finck * Translate between a swap entry and a file and offset pair.
95c2c66affSColin Finck */
96c2c66affSColin Finck #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
97c2c66affSColin Finck #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
98c2c66affSColin Finck #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
99c2c66affSColin Finck
100c2c66affSColin Finck /* Make sure there can be only 16 paging files */
101c2c66affSColin Finck C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES);
102c2c66affSColin Finck
103c2c66affSColin Finck static BOOLEAN MmSwapSpaceMessage = FALSE;
104c2c66affSColin Finck
105108991a6SPierre Schweitzer static BOOLEAN MmSystemPageFileLocated = FALSE;
106108991a6SPierre Schweitzer
107c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
108c2c66affSColin Finck
109c2c66affSColin Finck VOID
110c2c66affSColin Finck NTAPI
MmBuildMdlFromPages(PMDL Mdl,PPFN_NUMBER Pages)111c2c66affSColin Finck MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages)
112c2c66affSColin Finck {
113c2c66affSColin Finck memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE));
114c2c66affSColin Finck }
115c2c66affSColin Finck
116c2c66affSColin Finck
117c2c66affSColin Finck BOOLEAN
118c2c66affSColin Finck NTAPI
MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)119c2c66affSColin Finck MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)
120c2c66affSColin Finck {
121c2c66affSColin Finck ULONG i;
122c2c66affSColin Finck
123c2c66affSColin Finck /* Loop through all the paging files */
124c2c66affSColin Finck for (i = 0; i < MmNumberOfPagingFiles; i++)
125c2c66affSColin Finck {
126c2c66affSColin Finck /* Check if this is one of them */
127f106c297SPierre Schweitzer if (MmPagingFile[i]->FileObject == FileObject) return TRUE;
128c2c66affSColin Finck }
129c2c66affSColin Finck
130c2c66affSColin Finck /* Nothing found */
131c2c66affSColin Finck return FALSE;
132c2c66affSColin Finck }
133c2c66affSColin Finck
134c2c66affSColin Finck VOID
135c2c66affSColin Finck NTAPI
MmShowOutOfSpaceMessagePagingFile(VOID)136c2c66affSColin Finck MmShowOutOfSpaceMessagePagingFile(VOID)
137c2c66affSColin Finck {
138c2c66affSColin Finck if (!MmSwapSpaceMessage)
139c2c66affSColin Finck {
140c2c66affSColin Finck DPRINT1("MM: Out of swap space.\n");
141c2c66affSColin Finck MmSwapSpaceMessage = TRUE;
142c2c66affSColin Finck }
143c2c66affSColin Finck }
144c2c66affSColin Finck
145c2c66affSColin Finck NTSTATUS
146c2c66affSColin Finck NTAPI
MmWriteToSwapPage(SWAPENTRY SwapEntry,PFN_NUMBER Page)147c2c66affSColin Finck MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
148c2c66affSColin Finck {
149c2c66affSColin Finck ULONG i;
150c2c66affSColin Finck ULONG_PTR offset;
151c2c66affSColin Finck LARGE_INTEGER file_offset;
152c2c66affSColin Finck IO_STATUS_BLOCK Iosb;
153c2c66affSColin Finck NTSTATUS Status;
154c2c66affSColin Finck KEVENT Event;
155*539c3165STimo Kreuzer UCHAR MdlBase[sizeof(MDL) + sizeof(PFN_NUMBER)];
156c2c66affSColin Finck PMDL Mdl = (PMDL)MdlBase;
157c2c66affSColin Finck
158c2c66affSColin Finck DPRINT("MmWriteToSwapPage\n");
159c2c66affSColin Finck
160c2c66affSColin Finck if (SwapEntry == 0)
161c2c66affSColin Finck {
162c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT);
163c2c66affSColin Finck return(STATUS_UNSUCCESSFUL);
164c2c66affSColin Finck }
165c2c66affSColin Finck
166c2c66affSColin Finck i = FILE_FROM_ENTRY(SwapEntry);
167c2c66affSColin Finck offset = OFFSET_FROM_ENTRY(SwapEntry) - 1;
168c2c66affSColin Finck
169f106c297SPierre Schweitzer if (MmPagingFile[i]->FileObject == NULL ||
170f106c297SPierre Schweitzer MmPagingFile[i]->FileObject->DeviceObject == NULL)
171c2c66affSColin Finck {
172c2c66affSColin Finck DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
173c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT);
174c2c66affSColin Finck }
175c2c66affSColin Finck
176c2c66affSColin Finck MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
177c2c66affSColin Finck MmBuildMdlFromPages(Mdl, &Page);
178c2c66affSColin Finck Mdl->MdlFlags |= MDL_PAGES_LOCKED;
179c2c66affSColin Finck
180c2c66affSColin Finck file_offset.QuadPart = offset * PAGE_SIZE;
181c2c66affSColin Finck
182c2c66affSColin Finck KeInitializeEvent(&Event, NotificationEvent, FALSE);
183f106c297SPierre Schweitzer Status = IoSynchronousPageWrite(MmPagingFile[i]->FileObject,
184c2c66affSColin Finck Mdl,
185c2c66affSColin Finck &file_offset,
186c2c66affSColin Finck &Event,
187c2c66affSColin Finck &Iosb);
188c2c66affSColin Finck if (Status == STATUS_PENDING)
189c2c66affSColin Finck {
190c2c66affSColin Finck KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
191c2c66affSColin Finck Status = Iosb.Status;
192c2c66affSColin Finck }
193c2c66affSColin Finck
194c2c66affSColin Finck if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
195c2c66affSColin Finck {
196c2c66affSColin Finck MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
197c2c66affSColin Finck }
198c2c66affSColin Finck return(Status);
199c2c66affSColin Finck }
200c2c66affSColin Finck
201c2c66affSColin Finck
202c2c66affSColin Finck NTSTATUS
203c2c66affSColin Finck NTAPI
MmReadFromSwapPage(SWAPENTRY SwapEntry,PFN_NUMBER Page)204c2c66affSColin Finck MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
205c2c66affSColin Finck {
206857dd4aeSJérôme Gardou return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry));
207c2c66affSColin Finck }
208c2c66affSColin Finck
209c2c66affSColin Finck NTSTATUS
210c2c66affSColin Finck NTAPI
MiReadPageFile(_In_ PFN_NUMBER Page,_In_ ULONG PageFileIndex,_In_ ULONG_PTR PageFileOffset)211c2c66affSColin Finck MiReadPageFile(
212c2c66affSColin Finck _In_ PFN_NUMBER Page,
213c2c66affSColin Finck _In_ ULONG PageFileIndex,
214c2c66affSColin Finck _In_ ULONG_PTR PageFileOffset)
215c2c66affSColin Finck {
216c2c66affSColin Finck LARGE_INTEGER file_offset;
217c2c66affSColin Finck IO_STATUS_BLOCK Iosb;
218c2c66affSColin Finck NTSTATUS Status;
219c2c66affSColin Finck KEVENT Event;
220*539c3165STimo Kreuzer UCHAR MdlBase[sizeof(MDL) + sizeof(PFN_NUMBER)];
221c2c66affSColin Finck PMDL Mdl = (PMDL)MdlBase;
22202b0ca08SPierre Schweitzer PMMPAGING_FILE PagingFile;
223c2c66affSColin Finck
224c2c66affSColin Finck DPRINT("MiReadSwapFile\n");
225c2c66affSColin Finck
226c2c66affSColin Finck if (PageFileOffset == 0)
227c2c66affSColin Finck {
228c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT);
229c2c66affSColin Finck return(STATUS_UNSUCCESSFUL);
230c2c66affSColin Finck }
231c2c66affSColin Finck
232857dd4aeSJérôme Gardou /* Normalize offset. */
233857dd4aeSJérôme Gardou PageFileOffset--;
234857dd4aeSJérôme Gardou
235c2c66affSColin Finck ASSERT(PageFileIndex < MAX_PAGING_FILES);
236c2c66affSColin Finck
237f106c297SPierre Schweitzer PagingFile = MmPagingFile[PageFileIndex];
238c2c66affSColin Finck
239c2c66affSColin Finck if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL)
240c2c66affSColin Finck {
241c2c66affSColin Finck DPRINT1("Bad paging file %u\n", PageFileIndex);
242c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT);
243c2c66affSColin Finck }
244c2c66affSColin Finck
245c2c66affSColin Finck MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
246c2c66affSColin Finck MmBuildMdlFromPages(Mdl, &Page);
247d8cdb89fSJérôme Gardou Mdl->MdlFlags |= MDL_PAGES_LOCKED | MDL_IO_PAGE_READ;
248c2c66affSColin Finck
249c2c66affSColin Finck file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
250c2c66affSColin Finck
251c2c66affSColin Finck KeInitializeEvent(&Event, NotificationEvent, FALSE);
252c2c66affSColin Finck Status = IoPageRead(PagingFile->FileObject,
253c2c66affSColin Finck Mdl,
254c2c66affSColin Finck &file_offset,
255c2c66affSColin Finck &Event,
256c2c66affSColin Finck &Iosb);
257c2c66affSColin Finck if (Status == STATUS_PENDING)
258c2c66affSColin Finck {
259c2c66affSColin Finck KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
260c2c66affSColin Finck Status = Iosb.Status;
261c2c66affSColin Finck }
262c2c66affSColin Finck if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
263c2c66affSColin Finck {
264c2c66affSColin Finck MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
265c2c66affSColin Finck }
266c2c66affSColin Finck return(Status);
267c2c66affSColin Finck }
268c2c66affSColin Finck
2695c7ce447SVictor Perevertkin CODE_SEG("INIT")
270b20f8151SSerge Gautherie VOID
271c2c66affSColin Finck NTAPI
MmInitPagingFile(VOID)272c2c66affSColin Finck MmInitPagingFile(VOID)
273c2c66affSColin Finck {
274c2c66affSColin Finck ULONG i;
275c2c66affSColin Finck
276315867d4SPierre Schweitzer KeInitializeGuardedMutex(&MmPageFileCreationLock);
277c2c66affSColin Finck
278c2c66affSColin Finck MiFreeSwapPages = 0;
279c2c66affSColin Finck MiUsedSwapPages = 0;
280c2c66affSColin Finck MiReservedSwapPages = 0;
281c2c66affSColin Finck
282c2c66affSColin Finck for (i = 0; i < MAX_PAGING_FILES; i++)
283c2c66affSColin Finck {
284f106c297SPierre Schweitzer MmPagingFile[i] = NULL;
285c2c66affSColin Finck }
286c2c66affSColin Finck MmNumberOfPagingFiles = 0;
287c2c66affSColin Finck }
288c2c66affSColin Finck
289c2c66affSColin Finck VOID
290c2c66affSColin Finck NTAPI
MmFreeSwapPage(SWAPENTRY Entry)291c2c66affSColin Finck MmFreeSwapPage(SWAPENTRY Entry)
292c2c66affSColin Finck {
293c2c66affSColin Finck ULONG i;
294c2c66affSColin Finck ULONG_PTR off;
29502b0ca08SPierre Schweitzer PMMPAGING_FILE PagingFile;
296c2c66affSColin Finck
297c2c66affSColin Finck i = FILE_FROM_ENTRY(Entry);
298c2c66affSColin Finck off = OFFSET_FROM_ENTRY(Entry) - 1;
299c2c66affSColin Finck
300315867d4SPierre Schweitzer KeAcquireGuardedMutex(&MmPageFileCreationLock);
301f106c297SPierre Schweitzer
302f106c297SPierre Schweitzer PagingFile = MmPagingFile[i];
303f106c297SPierre Schweitzer if (PagingFile == NULL)
304c2c66affSColin Finck {
305c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT);
306c2c66affSColin Finck }
307c2c66affSColin Finck
30819318dccSPierre Schweitzer RtlClearBit(PagingFile->Bitmap, off >> 5);
309c2c66affSColin Finck
31019318dccSPierre Schweitzer PagingFile->FreeSpace++;
31119318dccSPierre Schweitzer PagingFile->CurrentUsage--;
312c2c66affSColin Finck
313c2c66affSColin Finck MiFreeSwapPages++;
314c2c66affSColin Finck MiUsedSwapPages--;
3153703bbd6SKyle Katarn UpdateTotalCommittedPages(-1);
316c2c66affSColin Finck
317315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
318c2c66affSColin Finck }
319c2c66affSColin Finck
320c2c66affSColin Finck SWAPENTRY
321c2c66affSColin Finck NTAPI
MmAllocSwapPage(VOID)322c2c66affSColin Finck MmAllocSwapPage(VOID)
323c2c66affSColin Finck {
324c2c66affSColin Finck ULONG i;
325c2c66affSColin Finck ULONG off;
326c2c66affSColin Finck SWAPENTRY entry;
327c2c66affSColin Finck
328315867d4SPierre Schweitzer KeAcquireGuardedMutex(&MmPageFileCreationLock);
329c2c66affSColin Finck
330c2c66affSColin Finck if (MiFreeSwapPages == 0)
331c2c66affSColin Finck {
332315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
333c2c66affSColin Finck return(0);
334c2c66affSColin Finck }
335c2c66affSColin Finck
336c2c66affSColin Finck for (i = 0; i < MAX_PAGING_FILES; i++)
337c2c66affSColin Finck {
338f106c297SPierre Schweitzer if (MmPagingFile[i] != NULL &&
33919318dccSPierre Schweitzer MmPagingFile[i]->FreeSpace >= 1)
340c2c66affSColin Finck {
34119318dccSPierre Schweitzer off = RtlFindClearBitsAndSet(MmPagingFile[i]->Bitmap, 1, 0);
342c2c66affSColin Finck if (off == 0xFFFFFFFF)
343c2c66affSColin Finck {
344c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT);
345315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
346c2c66affSColin Finck return(STATUS_UNSUCCESSFUL);
347c2c66affSColin Finck }
348c2c66affSColin Finck MiUsedSwapPages++;
349c2c66affSColin Finck MiFreeSwapPages--;
3503703bbd6SKyle Katarn UpdateTotalCommittedPages(1);
3513703bbd6SKyle Katarn
352315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
353c2c66affSColin Finck
354c2c66affSColin Finck entry = ENTRY_FROM_FILE_OFFSET(i, off + 1);
355c2c66affSColin Finck return(entry);
356c2c66affSColin Finck }
357c2c66affSColin Finck }
358c2c66affSColin Finck
359315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
360c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT);
361c2c66affSColin Finck return(0);
362c2c66affSColin Finck }
363c2c66affSColin Finck
3644ac263c9SHermès Bélusca-Maïto NTSTATUS
3654ac263c9SHermès Bélusca-Maïto NTAPI
NtCreatePagingFile(_In_ PUNICODE_STRING FileName,_In_ PLARGE_INTEGER MinimumSize,_In_ PLARGE_INTEGER MaximumSize,_In_ ULONG Reserved)3664ac263c9SHermès Bélusca-Maïto NtCreatePagingFile(
3674ac263c9SHermès Bélusca-Maïto _In_ PUNICODE_STRING FileName,
3684ac263c9SHermès Bélusca-Maïto _In_ PLARGE_INTEGER MinimumSize,
3694ac263c9SHermès Bélusca-Maïto _In_ PLARGE_INTEGER MaximumSize,
3704ac263c9SHermès Bélusca-Maïto _In_ ULONG Reserved)
371c2c66affSColin Finck {
372c2c66affSColin Finck NTSTATUS Status;
373c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes;
374c2c66affSColin Finck HANDLE FileHandle;
375c2c66affSColin Finck IO_STATUS_BLOCK IoStatus;
376c2c66affSColin Finck PFILE_OBJECT FileObject;
37702b0ca08SPierre Schweitzer PMMPAGING_FILE PagingFile;
3787611cc2bSTimo Kreuzer SIZE_T AllocMapSize;
379c2c66affSColin Finck ULONG Count;
380c2c66affSColin Finck KPROCESSOR_MODE PreviousMode;
38134e8f451SPierre Schweitzer UNICODE_STRING PageFileName;
382bfc6a795SPierre Schweitzer LARGE_INTEGER SafeMinimumSize, SafeMaximumSize, AllocationSize;
38336c20dc5SPierre Schweitzer FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
38428b4b419SPierre Schweitzer SECURITY_DESCRIPTOR SecurityDescriptor;
38528b4b419SPierre Schweitzer PACL Dacl;
38634e8f451SPierre Schweitzer PWSTR Buffer;
38712e8d7feSPierre Schweitzer DEVICE_TYPE DeviceType;
388c2c66affSColin Finck
389315867d4SPierre Schweitzer PAGED_CODE();
390315867d4SPierre Schweitzer
39106d4fce5SHermès Bélusca-Maïto DPRINT("NtCreatePagingFile(FileName: '%wZ', MinimumSize: %I64d, MaximumSize: %I64d)\n",
39206d4fce5SHermès Bélusca-Maïto FileName, MinimumSize->QuadPart, MaximumSize->QuadPart);
39306d4fce5SHermès Bélusca-Maïto
394c2c66affSColin Finck if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
395c2c66affSColin Finck {
3960ad4ef60SPierre Schweitzer return STATUS_TOO_MANY_PAGING_FILES;
397c2c66affSColin Finck }
398c2c66affSColin Finck
399c2c66affSColin Finck PreviousMode = ExGetPreviousMode();
400c2c66affSColin Finck
401c2c66affSColin Finck if (PreviousMode != KernelMode)
402c2c66affSColin Finck {
4030ad4ef60SPierre Schweitzer if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE)
4040ad4ef60SPierre Schweitzer {
4050ad4ef60SPierre Schweitzer return STATUS_PRIVILEGE_NOT_HELD;
4060ad4ef60SPierre Schweitzer }
4070ad4ef60SPierre Schweitzer
408c2c66affSColin Finck _SEH2_TRY
409c2c66affSColin Finck {
410bfc6a795SPierre Schweitzer SafeMinimumSize = ProbeForReadLargeInteger(MinimumSize);
411c2c66affSColin Finck SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
41206d4fce5SHermès Bélusca-Maïto PageFileName = ProbeForReadUnicodeString(FileName);
413c2c66affSColin Finck }
414c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
415c2c66affSColin Finck {
416c2c66affSColin Finck /* Return the exception code */
417c2c66affSColin Finck _SEH2_YIELD(return _SEH2_GetExceptionCode());
418c2c66affSColin Finck }
419c2c66affSColin Finck _SEH2_END;
420c2c66affSColin Finck }
421c2c66affSColin Finck else
422c2c66affSColin Finck {
423bfc6a795SPierre Schweitzer SafeMinimumSize = *MinimumSize;
424c2c66affSColin Finck SafeMaximumSize = *MaximumSize;
42506d4fce5SHermès Bélusca-Maïto PageFileName = *FileName;
426c2c66affSColin Finck }
427c2c66affSColin Finck
42806d4fce5SHermès Bélusca-Maïto /*
429a4274ad5SHermès Bélusca-Maïto * Pagefiles cannot be larger than the platform-specific memory addressable
430a4274ad5SHermès Bélusca-Maïto * limits, and of course the minimum should be smaller than the maximum.
43106d4fce5SHermès Bélusca-Maïto */
432a4274ad5SHermès Bélusca-Maïto if (SafeMinimumSize.QuadPart < MINIMUM_PAGEFILE_SIZE ||
433a4274ad5SHermès Bélusca-Maïto SafeMinimumSize.QuadPart > MAXIMUM_PAGEFILE_SIZE)
434c2c66affSColin Finck {
435c2c66affSColin Finck return STATUS_INVALID_PARAMETER_2;
436c2c66affSColin Finck }
437a4274ad5SHermès Bélusca-Maïto if (SafeMaximumSize.QuadPart < SafeMinimumSize.QuadPart ||
438a4274ad5SHermès Bélusca-Maïto SafeMaximumSize.QuadPart > MAXIMUM_PAGEFILE_SIZE)
439c2c66affSColin Finck {
440c2c66affSColin Finck return STATUS_INVALID_PARAMETER_3;
441c2c66affSColin Finck }
442c2c66affSColin Finck
44306d4fce5SHermès Bélusca-Maïto /* Validate the name length */
44406d4fce5SHermès Bélusca-Maïto if ((PageFileName.Length == 0) ||
445a4274ad5SHermès Bélusca-Maïto (PageFileName.Length > MAXIMUM_FILENAME_LENGTH))
446c2c66affSColin Finck {
44734e8f451SPierre Schweitzer return STATUS_OBJECT_NAME_INVALID;
448c2c66affSColin Finck }
449c2c66affSColin Finck
450a4274ad5SHermès Bélusca-Maïto /* Allocate a buffer to keep the name copy. Note that it is kept only
451a4274ad5SHermès Bélusca-Maïto * for information purposes, so it gets allocated in the paged pool,
452a4274ad5SHermès Bélusca-Maïto * even if it will be stored in the PagingFile structure, that is
453a4274ad5SHermès Bélusca-Maïto * allocated from non-paged pool (see below). */
45434e8f451SPierre Schweitzer PageFileName.MaximumLength = PageFileName.Length;
45534e8f451SPierre Schweitzer Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
45634e8f451SPierre Schweitzer if (Buffer == NULL)
45734e8f451SPierre Schweitzer {
45834e8f451SPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
45934e8f451SPierre Schweitzer }
46034e8f451SPierre Schweitzer
46106d4fce5SHermès Bélusca-Maïto /* Copy the name */
46234e8f451SPierre Schweitzer if (PreviousMode != KernelMode)
46334e8f451SPierre Schweitzer {
46434e8f451SPierre Schweitzer _SEH2_TRY
46534e8f451SPierre Schweitzer {
46634e8f451SPierre Schweitzer ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR));
46734e8f451SPierre Schweitzer RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
46834e8f451SPierre Schweitzer }
46934e8f451SPierre Schweitzer _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
47034e8f451SPierre Schweitzer {
47134e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
47234e8f451SPierre Schweitzer
47334e8f451SPierre Schweitzer /* Return the exception code */
47434e8f451SPierre Schweitzer _SEH2_YIELD(return _SEH2_GetExceptionCode());
47534e8f451SPierre Schweitzer }
47634e8f451SPierre Schweitzer _SEH2_END;
47734e8f451SPierre Schweitzer }
47834e8f451SPierre Schweitzer else
47934e8f451SPierre Schweitzer {
48034e8f451SPierre Schweitzer RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
48134e8f451SPierre Schweitzer }
48234e8f451SPierre Schweitzer
48306d4fce5SHermès Bélusca-Maïto /* Replace caller's buffer with ours */
48434e8f451SPierre Schweitzer PageFileName.Buffer = Buffer;
48534e8f451SPierre Schweitzer
48628b4b419SPierre Schweitzer /* Create the security descriptor for the page file */
48728b4b419SPierre Schweitzer Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
48828b4b419SPierre Schweitzer if (!NT_SUCCESS(Status))
48928b4b419SPierre Schweitzer {
49034e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
49128b4b419SPierre Schweitzer return Status;
49228b4b419SPierre Schweitzer }
49328b4b419SPierre Schweitzer
49428b4b419SPierre Schweitzer /* Create the DACL: we will only allow two SIDs */
49528b4b419SPierre Schweitzer Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
49628b4b419SPierre Schweitzer (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
497ab5fdac9SHermès Bélusca-Maïto Dacl = ExAllocatePoolWithTag(PagedPool, Count, TAG_DACL);
49828b4b419SPierre Schweitzer if (Dacl == NULL)
49928b4b419SPierre Schweitzer {
50034e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
50128b4b419SPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
50228b4b419SPierre Schweitzer }
50328b4b419SPierre Schweitzer
50428b4b419SPierre Schweitzer /* Initialize the DACL */
50528b4b419SPierre Schweitzer Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
50628b4b419SPierre Schweitzer if (!NT_SUCCESS(Status))
507a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
50828b4b419SPierre Schweitzer
50928b4b419SPierre Schweitzer /* Grant full access to admins */
51028b4b419SPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid);
51128b4b419SPierre Schweitzer if (!NT_SUCCESS(Status))
512a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
51328b4b419SPierre Schweitzer
51428b4b419SPierre Schweitzer /* Grant full access to SYSTEM */
51528b4b419SPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid);
51628b4b419SPierre Schweitzer if (!NT_SUCCESS(Status))
517a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
51828b4b419SPierre Schweitzer
51928b4b419SPierre Schweitzer /* Attach the DACL to the security descriptor */
52028b4b419SPierre Schweitzer Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
52128b4b419SPierre Schweitzer if (!NT_SUCCESS(Status))
522a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
52328b4b419SPierre Schweitzer
524c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes,
52534e8f451SPierre Schweitzer &PageFileName,
526a4274ad5SHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
527c2c66affSColin Finck NULL,
52828b4b419SPierre Schweitzer &SecurityDescriptor);
529c2c66affSColin Finck
5302969c28aSPierre Schweitzer /* Make sure we can at least store a complete page:
5312969c28aSPierre Schweitzer * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
5322969c28aSPierre Schweitzer * a problem if the paging file is fragmented. Suppose the first cluster
5332969c28aSPierre Schweitzer * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
5342969c28aSPierre Schweitzer * paging file but of another file. We can't write a complete page (4096
5352969c28aSPierre Schweitzer * bytes) to the physical location of cluster 3042 then. */
536bfc6a795SPierre Schweitzer AllocationSize.QuadPart = SafeMinimumSize.QuadPart + PAGE_SIZE;
5372969c28aSPierre Schweitzer
5382969c28aSPierre Schweitzer /* First, attempt to replace the page file, if existing */
539c2c66affSColin Finck Status = IoCreateFile(&FileHandle,
5402969c28aSPierre Schweitzer SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA,
541c2c66affSColin Finck &ObjectAttributes,
542c2c66affSColin Finck &IoStatus,
5432969c28aSPierre Schweitzer &AllocationSize,
5442969c28aSPierre Schweitzer FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5452969c28aSPierre Schweitzer FILE_SHARE_WRITE,
5462969c28aSPierre Schweitzer FILE_SUPERSEDE,
5472969c28aSPierre Schweitzer FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
548c2c66affSColin Finck NULL,
549c2c66affSColin Finck 0,
550c2c66affSColin Finck CreateFileTypeNone,
551c2c66affSColin Finck NULL,
552a4274ad5SHermès Bélusca-Maïto IO_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
5532969c28aSPierre Schweitzer /* If we failed, relax a bit constraints, someone may be already holding the
5542969c28aSPierre Schweitzer * the file, so share write, don't attempt to replace and don't delete on close
555a4274ad5SHermès Bélusca-Maïto * (basically, don't do anything conflicting).
5565bd938bdSPierre Schweitzer * This can happen if the caller attempts to extend a page file.
5572969c28aSPierre Schweitzer */
5582969c28aSPierre Schweitzer if (!NT_SUCCESS(Status))
5592969c28aSPierre Schweitzer {
5605bd938bdSPierre Schweitzer ULONG i;
5615bd938bdSPierre Schweitzer
5622969c28aSPierre Schweitzer Status = IoCreateFile(&FileHandle,
5632969c28aSPierre Schweitzer SYNCHRONIZE | FILE_WRITE_DATA,
5642969c28aSPierre Schweitzer &ObjectAttributes,
5652969c28aSPierre Schweitzer &IoStatus,
5662969c28aSPierre Schweitzer &AllocationSize,
5672969c28aSPierre Schweitzer FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5682969c28aSPierre Schweitzer FILE_SHARE_WRITE | FILE_SHARE_READ,
5692969c28aSPierre Schweitzer FILE_OPEN,
5702969c28aSPierre Schweitzer FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
5712969c28aSPierre Schweitzer NULL,
5722969c28aSPierre Schweitzer 0,
5732969c28aSPierre Schweitzer CreateFileTypeNone,
5742969c28aSPierre Schweitzer NULL,
575a4274ad5SHermès Bélusca-Maïto IO_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
5765bd938bdSPierre Schweitzer if (!NT_SUCCESS(Status))
577a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
5785bd938bdSPierre Schweitzer
5795bd938bdSPierre Schweitzer /* We opened it! Check we are that "someone" ;-)
5805bd938bdSPierre Schweitzer * First, get the opened file object.
5815bd938bdSPierre Schweitzer */
5825bd938bdSPierre Schweitzer Status = ObReferenceObjectByHandle(FileHandle,
5835bd938bdSPierre Schweitzer FILE_READ_DATA | FILE_WRITE_DATA,
5845bd938bdSPierre Schweitzer IoFileObjectType,
5855bd938bdSPierre Schweitzer KernelMode,
5865bd938bdSPierre Schweitzer (PVOID*)&FileObject,
5875bd938bdSPierre Schweitzer NULL);
5885bd938bdSPierre Schweitzer if (!NT_SUCCESS(Status))
5895bd938bdSPierre Schweitzer {
5905bd938bdSPierre Schweitzer ZwClose(FileHandle);
591a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
5925bd938bdSPierre Schweitzer }
5935bd938bdSPierre Schweitzer
5945bd938bdSPierre Schweitzer /* Find if it matches a previous page file */
5955bd938bdSPierre Schweitzer PagingFile = NULL;
596315867d4SPierre Schweitzer
597315867d4SPierre Schweitzer KeAcquireGuardedMutex(&MmPageFileCreationLock);
5985bd938bdSPierre Schweitzer
599a4274ad5SHermès Bélusca-Maïto for (i = 0; i < MmNumberOfPagingFiles; ++i)
6005bd938bdSPierre Schweitzer {
601a4274ad5SHermès Bélusca-Maïto if (MmPagingFile[i]->FileObject->SectionObjectPointer == FileObject->SectionObjectPointer)
6025bd938bdSPierre Schweitzer {
603a4274ad5SHermès Bélusca-Maïto /* Same object pointer: this is the matching page file */
604a4274ad5SHermès Bélusca-Maïto PagingFile = MmPagingFile[i];
6055bd938bdSPierre Schweitzer break;
6065bd938bdSPierre Schweitzer }
6075bd938bdSPierre Schweitzer }
6085bd938bdSPierre Schweitzer
6095bd938bdSPierre Schweitzer /* If we didn't find the page file, fail */
6105bd938bdSPierre Schweitzer if (PagingFile == NULL)
6115bd938bdSPierre Schweitzer {
612315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
6135bd938bdSPierre Schweitzer ObDereferenceObject(FileObject);
6145bd938bdSPierre Schweitzer ZwClose(FileHandle);
615a4274ad5SHermès Bélusca-Maïto Status = STATUS_NOT_FOUND;
616a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
6175bd938bdSPierre Schweitzer }
6185bd938bdSPierre Schweitzer
6192fe4e713SPierre Schweitzer /* Don't allow page file shrinking */
620e392bdf9SPierre Schweitzer if (PagingFile->MinimumSize > (SafeMinimumSize.QuadPart >> PAGE_SHIFT))
6212fe4e713SPierre Schweitzer {
6222fe4e713SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
6232fe4e713SPierre Schweitzer ObDereferenceObject(FileObject);
6242fe4e713SPierre Schweitzer ZwClose(FileHandle);
625a4274ad5SHermès Bélusca-Maïto Status = STATUS_INVALID_PARAMETER_2;
626a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
6272fe4e713SPierre Schweitzer }
6282fe4e713SPierre Schweitzer
629e392bdf9SPierre Schweitzer if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize)
6302fe4e713SPierre Schweitzer {
6312fe4e713SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
6322fe4e713SPierre Schweitzer ObDereferenceObject(FileObject);
6332fe4e713SPierre Schweitzer ZwClose(FileHandle);
634a4274ad5SHermès Bélusca-Maïto Status = STATUS_INVALID_PARAMETER_3;
635a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
6362fe4e713SPierre Schweitzer }
6372fe4e713SPierre Schweitzer
6385bd938bdSPierre Schweitzer /* FIXME: implement parameters checking and page file extension */
6395bd938bdSPierre Schweitzer UNIMPLEMENTED;
6405bd938bdSPierre Schweitzer
641315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
6425bd938bdSPierre Schweitzer ObDereferenceObject(FileObject);
6435bd938bdSPierre Schweitzer ZwClose(FileHandle);
644a4274ad5SHermès Bélusca-Maïto Status = STATUS_NOT_IMPLEMENTED;
645a4274ad5SHermès Bélusca-Maïto goto EarlyQuit;
6462969c28aSPierre Schweitzer }
647c2c66affSColin Finck
648c2c66affSColin Finck if (!NT_SUCCESS(Status))
649c2c66affSColin Finck {
650a4274ad5SHermès Bélusca-Maïto EarlyQuit:
6512969c28aSPierre Schweitzer DPRINT1("Failed creating page file: %lx\n", Status);
652ab5fdac9SHermès Bélusca-Maïto ExFreePoolWithTag(Dacl, TAG_DACL);
65334e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
65434e8f451SPierre Schweitzer return Status;
655c2c66affSColin Finck }
656c2c66affSColin Finck
65728b4b419SPierre Schweitzer /* Set the security descriptor */
65828b4b419SPierre Schweitzer if (NT_SUCCESS(IoStatus.Status))
65928b4b419SPierre Schweitzer {
66028b4b419SPierre Schweitzer Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor);
66128b4b419SPierre Schweitzer if (!NT_SUCCESS(Status))
66228b4b419SPierre Schweitzer {
66328b4b419SPierre Schweitzer ZwClose(FileHandle);
664ab5fdac9SHermès Bélusca-Maïto ExFreePoolWithTag(Dacl, TAG_DACL);
66534e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
66628b4b419SPierre Schweitzer return Status;
66728b4b419SPierre Schweitzer }
66828b4b419SPierre Schweitzer }
66928b4b419SPierre Schweitzer
67028b4b419SPierre Schweitzer /* DACL is no longer needed, free it */
671ab5fdac9SHermès Bélusca-Maïto ExFreePoolWithTag(Dacl, TAG_DACL);
67228b4b419SPierre Schweitzer
673ab5fdac9SHermès Bélusca-Maïto /* FIXME: To enable once page file management is moved to ARM3 */
6748281f4baSPierre Schweitzer #if 0
6758281f4baSPierre Schweitzer /* Check we won't overflow commit limit with the page file */
6768281f4baSPierre Schweitzer if (MmTotalCommitLimitMaximum + (SafeMaximumSize.QuadPart >> PAGE_SHIFT) <= MmTotalCommitLimitMaximum)
6778281f4baSPierre Schweitzer {
6788281f4baSPierre Schweitzer ZwClose(FileHandle);
6798281f4baSPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
6808281f4baSPierre Schweitzer return STATUS_INVALID_PARAMETER_3;
6818281f4baSPierre Schweitzer }
6828281f4baSPierre Schweitzer #endif
6838281f4baSPierre Schweitzer
684bfc6a795SPierre Schweitzer /* Set its end of file to minimal size */
685c2c66affSColin Finck Status = ZwSetInformationFile(FileHandle,
686c2c66affSColin Finck &IoStatus,
687bfc6a795SPierre Schweitzer &SafeMinimumSize,
688c2c66affSColin Finck sizeof(LARGE_INTEGER),
6892969c28aSPierre Schweitzer FileEndOfFileInformation);
6902969c28aSPierre Schweitzer if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status))
691c2c66affSColin Finck {
692c2c66affSColin Finck ZwClose(FileHandle);
69334e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
69434e8f451SPierre Schweitzer return Status;
695c2c66affSColin Finck }
696c2c66affSColin Finck
697c2c66affSColin Finck Status = ObReferenceObjectByHandle(FileHandle,
698cc59c973SPierre Schweitzer FILE_READ_DATA | FILE_WRITE_DATA,
699c2c66affSColin Finck IoFileObjectType,
700c2c66affSColin Finck KernelMode,
701c2c66affSColin Finck (PVOID*)&FileObject,
702c2c66affSColin Finck NULL);
703c2c66affSColin Finck if (!NT_SUCCESS(Status))
704c2c66affSColin Finck {
705c2c66affSColin Finck ZwClose(FileHandle);
70634e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
70734e8f451SPierre Schweitzer return Status;
708c2c66affSColin Finck }
709c2c66affSColin Finck
71012e8d7feSPierre Schweitzer /* Only allow page file on a few device types */
71112e8d7feSPierre Schweitzer DeviceType = IoGetRelatedDeviceObject(FileObject)->DeviceType;
712a4274ad5SHermès Bélusca-Maïto if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
713a4274ad5SHermès Bélusca-Maïto DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
714a4274ad5SHermès Bélusca-Maïto DeviceType != FILE_DEVICE_DFS_VOLUME &&
715a4274ad5SHermès Bélusca-Maïto DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
71612e8d7feSPierre Schweitzer {
71712e8d7feSPierre Schweitzer ObDereferenceObject(FileObject);
71812e8d7feSPierre Schweitzer ZwClose(FileHandle);
71912e8d7feSPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
72012e8d7feSPierre Schweitzer return Status;
72112e8d7feSPierre Schweitzer }
72212e8d7feSPierre Schweitzer
72336c20dc5SPierre Schweitzer /* Deny page file creation on a floppy disk */
72436c20dc5SPierre Schweitzer FsDeviceInfo.Characteristics = 0;
725a4274ad5SHermès Bélusca-Maïto IoQueryVolumeInformation(FileObject, FileFsDeviceInformation,
726a4274ad5SHermès Bélusca-Maïto sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
72736c20dc5SPierre Schweitzer if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
72836c20dc5SPierre Schweitzer {
72936c20dc5SPierre Schweitzer ObDereferenceObject(FileObject);
73036c20dc5SPierre Schweitzer ZwClose(FileHandle);
73134e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
73236c20dc5SPierre Schweitzer return STATUS_FLOPPY_VOLUME;
73336c20dc5SPierre Schweitzer }
73436c20dc5SPierre Schweitzer
735a4274ad5SHermès Bélusca-Maïto /*
736a4274ad5SHermès Bélusca-Maïto * Missing validation steps TODO:
737a4274ad5SHermès Bélusca-Maïto * (see https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/mm/modwrite/create.htm )
738a4274ad5SHermès Bélusca-Maïto *
739a4274ad5SHermès Bélusca-Maïto * - Verify that no file system driver or any filter driver has done file
740a4274ad5SHermès Bélusca-Maïto * I/O while opening the file.
741a4274ad5SHermès Bélusca-Maïto * Verify that nothing of the paging file is yet in memory. Specifically,
742a4274ad5SHermès Bélusca-Maïto * the file object must either have no SectionObjectPointer or the latter
743a4274ad5SHermès Bélusca-Maïto * must have neither a DataSectionObject nor an ImageSectionObject.
744a4274ad5SHermès Bélusca-Maïto * Otherwise, we should fail, returning STATUS_INCOMPATIBLE_FILE_MAP.
745a4274ad5SHermès Bélusca-Maïto *
746a4274ad5SHermès Bélusca-Maïto * - Inform all the applicable drivers to prepare for the possibility of
747a4274ad5SHermès Bélusca-Maïto * paging I/O. Much of the point to paging I/O is to resolve page faults.
748a4274ad5SHermès Bélusca-Maïto * Especially important is that drivers that handle paging I/O do not
749a4274ad5SHermès Bélusca-Maïto * cause more page faults. All the code and data that each driver might
750a4274ad5SHermès Bélusca-Maïto * ever use for access to the paging file must be locked into physical
751a4274ad5SHermès Bélusca-Maïto * memory. This can’t be left until paging I/O actually occurs.
752a4274ad5SHermès Bélusca-Maïto * It must be done in advance.
753a4274ad5SHermès Bélusca-Maïto */
754a4274ad5SHermès Bélusca-Maïto
755a4274ad5SHermès Bélusca-Maïto PagingFile = ExAllocatePoolZero(NonPagedPool, sizeof(*PagingFile), TAG_MM);
756c2c66affSColin Finck if (PagingFile == NULL)
757c2c66affSColin Finck {
758c2c66affSColin Finck ObDereferenceObject(FileObject);
759c2c66affSColin Finck ZwClose(FileHandle);
76034e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
7611ea68d05SPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
762c2c66affSColin Finck }
763c2c66affSColin Finck
7642969c28aSPierre Schweitzer PagingFile->FileHandle = FileHandle;
765c2c66affSColin Finck PagingFile->FileObject = FileObject;
76619318dccSPierre Schweitzer PagingFile->Size = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
767a4274ad5SHermès Bélusca-Maïto PagingFile->MinimumSize = PagingFile->Size;
768a4274ad5SHermès Bélusca-Maïto PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT);
76919318dccSPierre Schweitzer /* First page is never used: it's the header
77019318dccSPierre Schweitzer * TODO: write it
77119318dccSPierre Schweitzer */
772a4274ad5SHermès Bélusca-Maïto PagingFile->FreeSpace = PagingFile->Size - 1;
77319318dccSPierre Schweitzer PagingFile->CurrentUsage = 0;
77434e8f451SPierre Schweitzer PagingFile->PageFileName = PageFileName;
77519318dccSPierre Schweitzer ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage + 1);
776c2c66affSColin Finck
77719318dccSPierre Schweitzer AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->MaximumSize + 31) / 32) * sizeof(ULONG));
77819318dccSPierre Schweitzer PagingFile->Bitmap = ExAllocatePoolWithTag(NonPagedPool,
779f080ee13SPierre Schweitzer AllocMapSize,
780f080ee13SPierre Schweitzer TAG_MM);
78119318dccSPierre Schweitzer if (PagingFile->Bitmap == NULL)
782c2c66affSColin Finck {
7831ea68d05SPierre Schweitzer ExFreePoolWithTag(PagingFile, TAG_MM);
784c2c66affSColin Finck ObDereferenceObject(FileObject);
785c2c66affSColin Finck ZwClose(FileHandle);
78634e8f451SPierre Schweitzer ExFreePoolWithTag(Buffer, TAG_MM);
7871ea68d05SPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
788c2c66affSColin Finck }
789c2c66affSColin Finck
79019318dccSPierre Schweitzer RtlInitializeBitMap(PagingFile->Bitmap,
79119318dccSPierre Schweitzer (PULONG)(PagingFile->Bitmap + 1),
79219318dccSPierre Schweitzer (ULONG)(PagingFile->MaximumSize));
79319318dccSPierre Schweitzer RtlClearAllBits(PagingFile->Bitmap);
794c2c66affSColin Finck
795a4274ad5SHermès Bélusca-Maïto /* Insert the new paging file information into the list */
796315867d4SPierre Schweitzer KeAcquireGuardedMutex(&MmPageFileCreationLock);
797a4274ad5SHermès Bélusca-Maïto /* Ensure the corresponding slot is empty yet */
79802b0ca08SPierre Schweitzer ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
799f106c297SPierre Schweitzer MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
80002b0ca08SPierre Schweitzer MmNumberOfPagingFiles++;
80119318dccSPierre Schweitzer MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreeSpace;
802315867d4SPierre Schweitzer KeReleaseGuardedMutex(&MmPageFileCreationLock);
803c2c66affSColin Finck
804c2c66affSColin Finck MmSwapSpaceMessage = FALSE;
805c2c66affSColin Finck
806108991a6SPierre Schweitzer if (!MmSystemPageFileLocated && BooleanFlagOn(FileObject->DeviceObject->Flags, DO_SYSTEM_BOOT_PARTITION))
807108991a6SPierre Schweitzer {
808108991a6SPierre Schweitzer MmSystemPageFileLocated = IoInitializeCrashDump(FileHandle);
809108991a6SPierre Schweitzer }
810108991a6SPierre Schweitzer
8111ea68d05SPierre Schweitzer return STATUS_SUCCESS;
812c2c66affSColin Finck }
813c2c66affSColin Finck
814c2c66affSColin Finck /* EOF */
815