xref: /reactos/ntoskrnl/mm/pagefile.c (revision 539c3165)
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