1c2c66affSColin Finck /* 2c2c66affSColin Finck * ReactOS kernel 3c2c66affSColin Finck * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team 4c2c66affSColin Finck * 5c2c66affSColin Finck * This program is free software; you can redistribute it and/or modify 6c2c66affSColin Finck * it under the terms of the GNU General Public License as published by 7c2c66affSColin Finck * the Free Software Foundation; either version 2 of the License, or 8c2c66affSColin Finck * (at your option) any later version. 9c2c66affSColin Finck * 10c2c66affSColin Finck * This program is distributed in the hope that it will be useful, 11c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of 12c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13c2c66affSColin Finck * GNU General Public License for more details. 14c2c66affSColin Finck * 15c2c66affSColin Finck * You should have received a copy of the GNU General Public License along 16c2c66affSColin Finck * with this program; if not, write to the Free Software Foundation, Inc., 17c2c66affSColin Finck * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18c2c66affSColin Finck */ 19c2c66affSColin Finck /* 20c2c66affSColin Finck * PROJECT: ReactOS kernel 21c2c66affSColin Finck * FILE: ntoskrnl/mm/pagefile.c 22c2c66affSColin Finck * PURPOSE: Paging file functions 23c2c66affSColin Finck * PROGRAMMER: David Welch (welch@mcmail.com) 24c2c66affSColin Finck * UPDATE HISTORY: 25c2c66affSColin Finck * Created 22/05/98 26c2c66affSColin Finck */ 27c2c66affSColin Finck 28c2c66affSColin Finck /* INCLUDES *****************************************************************/ 29c2c66affSColin Finck 30c2c66affSColin Finck #include <ntoskrnl.h> 31c2c66affSColin Finck #define NDEBUG 32c2c66affSColin Finck #include <debug.h> 33c2c66affSColin Finck 34c2c66affSColin Finck #if defined (ALLOC_PRAGMA) 35c2c66affSColin Finck #pragma alloc_text(INIT, MmInitPagingFile) 36c2c66affSColin Finck #endif 37c2c66affSColin Finck 38c2c66affSColin Finck PVOID 39c2c66affSColin Finck NTAPI 40c2c66affSColin Finck MiFindExportedRoutineByName(IN PVOID DllBase, 41c2c66affSColin Finck IN PANSI_STRING ExportName); 42c2c66affSColin Finck 43c2c66affSColin Finck /* TYPES *********************************************************************/ 44c2c66affSColin Finck 45c2c66affSColin Finck typedef struct _PAGINGFILE 46c2c66affSColin Finck { 47c2c66affSColin Finck PFILE_OBJECT FileObject; 482969c28aSPierre Schweitzer HANDLE FileHandle; 49c2c66affSColin Finck LARGE_INTEGER MaximumSize; 50c2c66affSColin Finck LARGE_INTEGER CurrentSize; 51c2c66affSColin Finck PFN_NUMBER FreePages; 52c2c66affSColin Finck PFN_NUMBER UsedPages; 53*f080ee13SPierre Schweitzer PRTL_BITMAP AllocMap; 54c2c66affSColin Finck KSPIN_LOCK AllocMapLock; 55c2c66affSColin Finck } 56c2c66affSColin Finck PAGINGFILE, *PPAGINGFILE; 57c2c66affSColin Finck 58c2c66affSColin Finck /* GLOBALS *******************************************************************/ 59c2c66affSColin Finck 60c2c66affSColin Finck #define PAIRS_PER_RUN (1024) 61c2c66affSColin Finck 62c2c66affSColin Finck #define MAX_PAGING_FILES (16) 63c2c66affSColin Finck 64c2c66affSColin Finck /* List of paging files, both used and free */ 65c2c66affSColin Finck static PPAGINGFILE PagingFileList[MAX_PAGING_FILES]; 66c2c66affSColin Finck 67c2c66affSColin Finck /* Lock for examining the list of paging files */ 68c2c66affSColin Finck static KSPIN_LOCK PagingFileListLock; 69c2c66affSColin Finck 70c2c66affSColin Finck /* Number of paging files */ 71c2c66affSColin Finck ULONG MmNumberOfPagingFiles; 72c2c66affSColin Finck 73c2c66affSColin Finck /* Number of pages that are available for swapping */ 74c2c66affSColin Finck PFN_COUNT MiFreeSwapPages; 75c2c66affSColin Finck 76c2c66affSColin Finck /* Number of pages that have been allocated for swapping */ 77c2c66affSColin Finck PFN_COUNT MiUsedSwapPages; 78c2c66affSColin Finck 79c2c66affSColin Finck BOOLEAN MmZeroPageFile; 80c2c66affSColin Finck 81c2c66affSColin Finck /* 82c2c66affSColin Finck * Number of pages that have been reserved for swapping but not yet allocated 83c2c66affSColin Finck */ 84c2c66affSColin Finck static PFN_COUNT MiReservedSwapPages; 85c2c66affSColin Finck 86c2c66affSColin Finck /* 87c2c66affSColin Finck * Ratio between reserved and available swap pages, e.g. setting this to five 88c2c66affSColin Finck * forces one swap page to be available for every five swap pages that are 89c2c66affSColin Finck * reserved. Setting this to zero turns off commit checking altogether. 90c2c66affSColin Finck */ 91c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_RATIO (1) 92c2c66affSColin Finck 93c2c66affSColin Finck /* 94c2c66affSColin Finck * Number of pages that can be used for potentially swapable memory without 95c2c66affSColin Finck * pagefile space being reserved. The intention is that this allows smss 96c2c66affSColin Finck * to start up and create page files while ordinarily having a commit 97c2c66affSColin Finck * ratio of one. 98c2c66affSColin Finck */ 99c2c66affSColin Finck #define MM_PAGEFILE_COMMIT_GRACE (256) 100c2c66affSColin Finck 101c2c66affSColin Finck /* 102c2c66affSColin Finck * Translate between a swap entry and a file and offset pair. 103c2c66affSColin Finck */ 104c2c66affSColin Finck #define FILE_FROM_ENTRY(i) ((i) & 0x0f) 105c2c66affSColin Finck #define OFFSET_FROM_ENTRY(i) ((i) >> 11) 106c2c66affSColin Finck #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400) 107c2c66affSColin Finck 108c2c66affSColin Finck /* Make sure there can be only 16 paging files */ 109c2c66affSColin Finck C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES); 110c2c66affSColin Finck 111c2c66affSColin Finck static BOOLEAN MmSwapSpaceMessage = FALSE; 112c2c66affSColin Finck 113c2c66affSColin Finck /* FUNCTIONS *****************************************************************/ 114c2c66affSColin Finck 115c2c66affSColin Finck VOID 116c2c66affSColin Finck NTAPI 117c2c66affSColin Finck MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages) 118c2c66affSColin Finck { 119c2c66affSColin Finck memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE)); 120c2c66affSColin Finck 121c2c66affSColin Finck /* FIXME: this flag should be set by the caller perhaps? */ 122c2c66affSColin Finck Mdl->MdlFlags |= MDL_IO_PAGE_READ; 123c2c66affSColin Finck } 124c2c66affSColin Finck 125c2c66affSColin Finck 126c2c66affSColin Finck BOOLEAN 127c2c66affSColin Finck NTAPI 128c2c66affSColin Finck MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject) 129c2c66affSColin Finck { 130c2c66affSColin Finck ULONG i; 131c2c66affSColin Finck 132c2c66affSColin Finck /* Loop through all the paging files */ 133c2c66affSColin Finck for (i = 0; i < MmNumberOfPagingFiles; i++) 134c2c66affSColin Finck { 135c2c66affSColin Finck /* Check if this is one of them */ 136c2c66affSColin Finck if (PagingFileList[i]->FileObject == FileObject) return TRUE; 137c2c66affSColin Finck } 138c2c66affSColin Finck 139c2c66affSColin Finck /* Nothing found */ 140c2c66affSColin Finck return FALSE; 141c2c66affSColin Finck } 142c2c66affSColin Finck 143c2c66affSColin Finck VOID 144c2c66affSColin Finck NTAPI 145c2c66affSColin Finck MmShowOutOfSpaceMessagePagingFile(VOID) 146c2c66affSColin Finck { 147c2c66affSColin Finck if (!MmSwapSpaceMessage) 148c2c66affSColin Finck { 149c2c66affSColin Finck DPRINT1("MM: Out of swap space.\n"); 150c2c66affSColin Finck MmSwapSpaceMessage = TRUE; 151c2c66affSColin Finck } 152c2c66affSColin Finck } 153c2c66affSColin Finck 154c2c66affSColin Finck NTSTATUS 155c2c66affSColin Finck NTAPI 156c2c66affSColin Finck MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 157c2c66affSColin Finck { 158c2c66affSColin Finck ULONG i; 159c2c66affSColin Finck ULONG_PTR offset; 160c2c66affSColin Finck LARGE_INTEGER file_offset; 161c2c66affSColin Finck IO_STATUS_BLOCK Iosb; 162c2c66affSColin Finck NTSTATUS Status; 163c2c66affSColin Finck KEVENT Event; 164c2c66affSColin Finck UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 165c2c66affSColin Finck PMDL Mdl = (PMDL)MdlBase; 166c2c66affSColin Finck 167c2c66affSColin Finck DPRINT("MmWriteToSwapPage\n"); 168c2c66affSColin Finck 169c2c66affSColin Finck if (SwapEntry == 0) 170c2c66affSColin Finck { 171c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 172c2c66affSColin Finck return(STATUS_UNSUCCESSFUL); 173c2c66affSColin Finck } 174c2c66affSColin Finck 175c2c66affSColin Finck i = FILE_FROM_ENTRY(SwapEntry); 176c2c66affSColin Finck offset = OFFSET_FROM_ENTRY(SwapEntry) - 1; 177c2c66affSColin Finck 178c2c66affSColin Finck if (PagingFileList[i]->FileObject == NULL || 179c2c66affSColin Finck PagingFileList[i]->FileObject->DeviceObject == NULL) 180c2c66affSColin Finck { 181c2c66affSColin Finck DPRINT1("Bad paging file 0x%.8X\n", SwapEntry); 182c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 183c2c66affSColin Finck } 184c2c66affSColin Finck 185c2c66affSColin Finck MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 186c2c66affSColin Finck MmBuildMdlFromPages(Mdl, &Page); 187c2c66affSColin Finck Mdl->MdlFlags |= MDL_PAGES_LOCKED; 188c2c66affSColin Finck 189c2c66affSColin Finck file_offset.QuadPart = offset * PAGE_SIZE; 190c2c66affSColin Finck 191c2c66affSColin Finck KeInitializeEvent(&Event, NotificationEvent, FALSE); 192c2c66affSColin Finck Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject, 193c2c66affSColin Finck Mdl, 194c2c66affSColin Finck &file_offset, 195c2c66affSColin Finck &Event, 196c2c66affSColin Finck &Iosb); 197c2c66affSColin Finck if (Status == STATUS_PENDING) 198c2c66affSColin Finck { 199c2c66affSColin Finck KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 200c2c66affSColin Finck Status = Iosb.Status; 201c2c66affSColin Finck } 202c2c66affSColin Finck 203c2c66affSColin Finck if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 204c2c66affSColin Finck { 205c2c66affSColin Finck MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 206c2c66affSColin Finck } 207c2c66affSColin Finck return(Status); 208c2c66affSColin Finck } 209c2c66affSColin Finck 210c2c66affSColin Finck 211c2c66affSColin Finck NTSTATUS 212c2c66affSColin Finck NTAPI 213c2c66affSColin Finck MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 214c2c66affSColin Finck { 215c2c66affSColin Finck return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry) - 1); 216c2c66affSColin Finck } 217c2c66affSColin Finck 218c2c66affSColin Finck NTSTATUS 219c2c66affSColin Finck NTAPI 220c2c66affSColin Finck MiReadPageFile( 221c2c66affSColin Finck _In_ PFN_NUMBER Page, 222c2c66affSColin Finck _In_ ULONG PageFileIndex, 223c2c66affSColin Finck _In_ ULONG_PTR PageFileOffset) 224c2c66affSColin Finck { 225c2c66affSColin Finck LARGE_INTEGER file_offset; 226c2c66affSColin Finck IO_STATUS_BLOCK Iosb; 227c2c66affSColin Finck NTSTATUS Status; 228c2c66affSColin Finck KEVENT Event; 229c2c66affSColin Finck UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 230c2c66affSColin Finck PMDL Mdl = (PMDL)MdlBase; 231c2c66affSColin Finck PPAGINGFILE PagingFile; 232c2c66affSColin Finck 233c2c66affSColin Finck DPRINT("MiReadSwapFile\n"); 234c2c66affSColin Finck 235c2c66affSColin Finck if (PageFileOffset == 0) 236c2c66affSColin Finck { 237c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 238c2c66affSColin Finck return(STATUS_UNSUCCESSFUL); 239c2c66affSColin Finck } 240c2c66affSColin Finck 241c2c66affSColin Finck ASSERT(PageFileIndex < MAX_PAGING_FILES); 242c2c66affSColin Finck 243c2c66affSColin Finck PagingFile = PagingFileList[PageFileIndex]; 244c2c66affSColin Finck 245c2c66affSColin Finck if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL) 246c2c66affSColin Finck { 247c2c66affSColin Finck DPRINT1("Bad paging file %u\n", PageFileIndex); 248c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 249c2c66affSColin Finck } 250c2c66affSColin Finck 251c2c66affSColin Finck MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 252c2c66affSColin Finck MmBuildMdlFromPages(Mdl, &Page); 253c2c66affSColin Finck Mdl->MdlFlags |= MDL_PAGES_LOCKED; 254c2c66affSColin Finck 255c2c66affSColin Finck file_offset.QuadPart = PageFileOffset * PAGE_SIZE; 256c2c66affSColin Finck 257c2c66affSColin Finck KeInitializeEvent(&Event, NotificationEvent, FALSE); 258c2c66affSColin Finck Status = IoPageRead(PagingFile->FileObject, 259c2c66affSColin Finck Mdl, 260c2c66affSColin Finck &file_offset, 261c2c66affSColin Finck &Event, 262c2c66affSColin Finck &Iosb); 263c2c66affSColin Finck if (Status == STATUS_PENDING) 264c2c66affSColin Finck { 265c2c66affSColin Finck KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 266c2c66affSColin Finck Status = Iosb.Status; 267c2c66affSColin Finck } 268c2c66affSColin Finck if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 269c2c66affSColin Finck { 270c2c66affSColin Finck MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 271c2c66affSColin Finck } 272c2c66affSColin Finck return(Status); 273c2c66affSColin Finck } 274c2c66affSColin Finck 275c2c66affSColin Finck VOID 276c2c66affSColin Finck INIT_FUNCTION 277c2c66affSColin Finck NTAPI 278c2c66affSColin Finck MmInitPagingFile(VOID) 279c2c66affSColin Finck { 280c2c66affSColin Finck ULONG i; 281c2c66affSColin Finck 282c2c66affSColin Finck KeInitializeSpinLock(&PagingFileListLock); 283c2c66affSColin Finck 284c2c66affSColin Finck MiFreeSwapPages = 0; 285c2c66affSColin Finck MiUsedSwapPages = 0; 286c2c66affSColin Finck MiReservedSwapPages = 0; 287c2c66affSColin Finck 288c2c66affSColin Finck for (i = 0; i < MAX_PAGING_FILES; i++) 289c2c66affSColin Finck { 290c2c66affSColin Finck PagingFileList[i] = NULL; 291c2c66affSColin Finck } 292c2c66affSColin Finck MmNumberOfPagingFiles = 0; 293c2c66affSColin Finck } 294c2c66affSColin Finck 295c2c66affSColin Finck static ULONG 296c2c66affSColin Finck MiAllocPageFromPagingFile(PPAGINGFILE PagingFile) 297c2c66affSColin Finck { 298c2c66affSColin Finck KIRQL oldIrql; 299*f080ee13SPierre Schweitzer ULONG off; 300c2c66affSColin Finck 301c2c66affSColin Finck KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql); 302*f080ee13SPierre Schweitzer off = RtlFindClearBitsAndSet(PagingFile->AllocMap, 1, 0); 303c2c66affSColin Finck KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql); 304c2c66affSColin Finck 305*f080ee13SPierre Schweitzer return off; 306c2c66affSColin Finck } 307c2c66affSColin Finck 308c2c66affSColin Finck VOID 309c2c66affSColin Finck NTAPI 310c2c66affSColin Finck MmFreeSwapPage(SWAPENTRY Entry) 311c2c66affSColin Finck { 312c2c66affSColin Finck ULONG i; 313c2c66affSColin Finck ULONG_PTR off; 314c2c66affSColin Finck KIRQL oldIrql; 315c2c66affSColin Finck 316c2c66affSColin Finck i = FILE_FROM_ENTRY(Entry); 317c2c66affSColin Finck off = OFFSET_FROM_ENTRY(Entry) - 1; 318c2c66affSColin Finck 319c2c66affSColin Finck KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 320c2c66affSColin Finck if (PagingFileList[i] == NULL) 321c2c66affSColin Finck { 322c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 323c2c66affSColin Finck } 324c2c66affSColin Finck KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock); 325c2c66affSColin Finck 326*f080ee13SPierre Schweitzer RtlClearBit(PagingFileList[i]->AllocMap, off >> 5); 327c2c66affSColin Finck 328c2c66affSColin Finck PagingFileList[i]->FreePages++; 329c2c66affSColin Finck PagingFileList[i]->UsedPages--; 330c2c66affSColin Finck 331c2c66affSColin Finck MiFreeSwapPages++; 332c2c66affSColin Finck MiUsedSwapPages--; 333c2c66affSColin Finck 334c2c66affSColin Finck KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock); 335c2c66affSColin Finck KeReleaseSpinLock(&PagingFileListLock, oldIrql); 336c2c66affSColin Finck } 337c2c66affSColin Finck 338c2c66affSColin Finck SWAPENTRY 339c2c66affSColin Finck NTAPI 340c2c66affSColin Finck MmAllocSwapPage(VOID) 341c2c66affSColin Finck { 342c2c66affSColin Finck KIRQL oldIrql; 343c2c66affSColin Finck ULONG i; 344c2c66affSColin Finck ULONG off; 345c2c66affSColin Finck SWAPENTRY entry; 346c2c66affSColin Finck 347c2c66affSColin Finck KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 348c2c66affSColin Finck 349c2c66affSColin Finck if (MiFreeSwapPages == 0) 350c2c66affSColin Finck { 351c2c66affSColin Finck KeReleaseSpinLock(&PagingFileListLock, oldIrql); 352c2c66affSColin Finck return(0); 353c2c66affSColin Finck } 354c2c66affSColin Finck 355c2c66affSColin Finck for (i = 0; i < MAX_PAGING_FILES; i++) 356c2c66affSColin Finck { 357c2c66affSColin Finck if (PagingFileList[i] != NULL && 358c2c66affSColin Finck PagingFileList[i]->FreePages >= 1) 359c2c66affSColin Finck { 360c2c66affSColin Finck off = MiAllocPageFromPagingFile(PagingFileList[i]); 361c2c66affSColin Finck if (off == 0xFFFFFFFF) 362c2c66affSColin Finck { 363c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 364c2c66affSColin Finck KeReleaseSpinLock(&PagingFileListLock, oldIrql); 365c2c66affSColin Finck return(STATUS_UNSUCCESSFUL); 366c2c66affSColin Finck } 367c2c66affSColin Finck MiUsedSwapPages++; 368c2c66affSColin Finck MiFreeSwapPages--; 369c2c66affSColin Finck KeReleaseSpinLock(&PagingFileListLock, oldIrql); 370c2c66affSColin Finck 371c2c66affSColin Finck entry = ENTRY_FROM_FILE_OFFSET(i, off + 1); 372c2c66affSColin Finck return(entry); 373c2c66affSColin Finck } 374c2c66affSColin Finck } 375c2c66affSColin Finck 376c2c66affSColin Finck KeReleaseSpinLock(&PagingFileListLock, oldIrql); 377c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 378c2c66affSColin Finck return(0); 379c2c66affSColin Finck } 380c2c66affSColin Finck 381c2c66affSColin Finck NTSTATUS NTAPI 382c2c66affSColin Finck NtCreatePagingFile(IN PUNICODE_STRING FileName, 383c2c66affSColin Finck IN PLARGE_INTEGER InitialSize, 384c2c66affSColin Finck IN PLARGE_INTEGER MaximumSize, 385c2c66affSColin Finck IN ULONG Reserved) 386c2c66affSColin Finck { 387c2c66affSColin Finck NTSTATUS Status; 388c2c66affSColin Finck OBJECT_ATTRIBUTES ObjectAttributes; 389c2c66affSColin Finck HANDLE FileHandle; 390c2c66affSColin Finck IO_STATUS_BLOCK IoStatus; 391c2c66affSColin Finck PFILE_OBJECT FileObject; 392c2c66affSColin Finck PPAGINGFILE PagingFile; 393c2c66affSColin Finck KIRQL oldIrql; 394c2c66affSColin Finck ULONG AllocMapSize; 395c2c66affSColin Finck ULONG i; 396c2c66affSColin Finck ULONG Count; 397c2c66affSColin Finck KPROCESSOR_MODE PreviousMode; 398c2c66affSColin Finck UNICODE_STRING CapturedFileName; 3992969c28aSPierre Schweitzer LARGE_INTEGER SafeInitialSize, SafeMaximumSize, AllocationSize; 40036c20dc5SPierre Schweitzer FILE_FS_DEVICE_INFORMATION FsDeviceInfo; 40128b4b419SPierre Schweitzer SECURITY_DESCRIPTOR SecurityDescriptor; 40228b4b419SPierre Schweitzer PACL Dacl; 403c2c66affSColin Finck 404c2c66affSColin Finck DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n", 405c2c66affSColin Finck FileName, InitialSize->QuadPart); 406c2c66affSColin Finck 407c2c66affSColin Finck if (MmNumberOfPagingFiles >= MAX_PAGING_FILES) 408c2c66affSColin Finck { 4090ad4ef60SPierre Schweitzer return STATUS_TOO_MANY_PAGING_FILES; 410c2c66affSColin Finck } 411c2c66affSColin Finck 412c2c66affSColin Finck PreviousMode = ExGetPreviousMode(); 413c2c66affSColin Finck 414c2c66affSColin Finck if (PreviousMode != KernelMode) 415c2c66affSColin Finck { 4160ad4ef60SPierre Schweitzer if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE) 4170ad4ef60SPierre Schweitzer { 4180ad4ef60SPierre Schweitzer return STATUS_PRIVILEGE_NOT_HELD; 4190ad4ef60SPierre Schweitzer } 4200ad4ef60SPierre Schweitzer 421c2c66affSColin Finck _SEH2_TRY 422c2c66affSColin Finck { 423c2c66affSColin Finck SafeInitialSize = ProbeForReadLargeInteger(InitialSize); 424c2c66affSColin Finck SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 425c2c66affSColin Finck } 426c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 427c2c66affSColin Finck { 428c2c66affSColin Finck /* Return the exception code */ 429c2c66affSColin Finck _SEH2_YIELD(return _SEH2_GetExceptionCode()); 430c2c66affSColin Finck } 431c2c66affSColin Finck _SEH2_END; 432c2c66affSColin Finck } 433c2c66affSColin Finck else 434c2c66affSColin Finck { 435c2c66affSColin Finck SafeInitialSize = *InitialSize; 436c2c66affSColin Finck SafeMaximumSize = *MaximumSize; 437c2c66affSColin Finck } 438c2c66affSColin Finck 439c2c66affSColin Finck /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be 440c2c66affSColin Finck smaller than the maximum */ 441c2c66affSColin Finck if (0 != SafeInitialSize.u.HighPart) 442c2c66affSColin Finck { 443c2c66affSColin Finck return STATUS_INVALID_PARAMETER_2; 444c2c66affSColin Finck } 445c2c66affSColin Finck if (0 != SafeMaximumSize.u.HighPart) 446c2c66affSColin Finck { 447c2c66affSColin Finck return STATUS_INVALID_PARAMETER_3; 448c2c66affSColin Finck } 449c2c66affSColin Finck if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart) 450c2c66affSColin Finck { 451c2c66affSColin Finck return STATUS_INVALID_PARAMETER_MIX; 452c2c66affSColin Finck } 453c2c66affSColin Finck 454c2c66affSColin Finck Status = ProbeAndCaptureUnicodeString(&CapturedFileName, 455c2c66affSColin Finck PreviousMode, 456c2c66affSColin Finck FileName); 457c2c66affSColin Finck if (!NT_SUCCESS(Status)) 458c2c66affSColin Finck { 459c2c66affSColin Finck return(Status); 460c2c66affSColin Finck } 461c2c66affSColin Finck 46228b4b419SPierre Schweitzer /* Create the security descriptor for the page file */ 46328b4b419SPierre Schweitzer Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); 46428b4b419SPierre Schweitzer if (!NT_SUCCESS(Status)) 46528b4b419SPierre Schweitzer { 46628b4b419SPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedFileName, 46728b4b419SPierre Schweitzer PreviousMode); 46828b4b419SPierre Schweitzer return Status; 46928b4b419SPierre Schweitzer } 47028b4b419SPierre Schweitzer 47128b4b419SPierre Schweitzer /* Create the DACL: we will only allow two SIDs */ 47228b4b419SPierre Schweitzer Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + 47328b4b419SPierre Schweitzer (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); 47428b4b419SPierre Schweitzer Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD'); 47528b4b419SPierre Schweitzer if (Dacl == NULL) 47628b4b419SPierre Schweitzer { 47728b4b419SPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedFileName, 47828b4b419SPierre Schweitzer PreviousMode); 47928b4b419SPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES; 48028b4b419SPierre Schweitzer } 48128b4b419SPierre Schweitzer 48228b4b419SPierre Schweitzer /* Initialize the DACL */ 48328b4b419SPierre Schweitzer Status = RtlCreateAcl(Dacl, Count, ACL_REVISION); 48428b4b419SPierre Schweitzer if (!NT_SUCCESS(Status)) 48528b4b419SPierre Schweitzer { 48628b4b419SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 48728b4b419SPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedFileName, 48828b4b419SPierre Schweitzer PreviousMode); 48928b4b419SPierre Schweitzer return Status; 49028b4b419SPierre Schweitzer } 49128b4b419SPierre Schweitzer 49228b4b419SPierre Schweitzer /* Grant full access to admins */ 49328b4b419SPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid); 49428b4b419SPierre Schweitzer if (!NT_SUCCESS(Status)) 49528b4b419SPierre Schweitzer { 49628b4b419SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 49728b4b419SPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedFileName, 49828b4b419SPierre Schweitzer PreviousMode); 49928b4b419SPierre Schweitzer return Status; 50028b4b419SPierre Schweitzer } 50128b4b419SPierre Schweitzer 50228b4b419SPierre Schweitzer /* Grant full access to SYSTEM */ 50328b4b419SPierre Schweitzer Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid); 50428b4b419SPierre Schweitzer if (!NT_SUCCESS(Status)) 50528b4b419SPierre Schweitzer { 50628b4b419SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 50728b4b419SPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedFileName, 50828b4b419SPierre Schweitzer PreviousMode); 50928b4b419SPierre Schweitzer return Status; 51028b4b419SPierre Schweitzer } 51128b4b419SPierre Schweitzer 51228b4b419SPierre Schweitzer /* Attach the DACL to the security descriptor */ 51328b4b419SPierre Schweitzer Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE); 51428b4b419SPierre Schweitzer if (!NT_SUCCESS(Status)) 51528b4b419SPierre Schweitzer { 51628b4b419SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 51728b4b419SPierre Schweitzer ReleaseCapturedUnicodeString(&CapturedFileName, 51828b4b419SPierre Schweitzer PreviousMode); 51928b4b419SPierre Schweitzer return Status; 52028b4b419SPierre Schweitzer } 52128b4b419SPierre Schweitzer 522c2c66affSColin Finck InitializeObjectAttributes(&ObjectAttributes, 523c2c66affSColin Finck &CapturedFileName, 524c2c66affSColin Finck OBJ_KERNEL_HANDLE, 525c2c66affSColin Finck NULL, 52628b4b419SPierre Schweitzer &SecurityDescriptor); 527c2c66affSColin Finck 5282969c28aSPierre Schweitzer /* Make sure we can at least store a complete page: 5292969c28aSPierre Schweitzer * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is 5302969c28aSPierre Schweitzer * a problem if the paging file is fragmented. Suppose the first cluster 5312969c28aSPierre Schweitzer * of the paging file is cluster 3042 but cluster 3043 is NOT part of the 5322969c28aSPierre Schweitzer * paging file but of another file. We can't write a complete page (4096 5332969c28aSPierre Schweitzer * bytes) to the physical location of cluster 3042 then. */ 5342969c28aSPierre Schweitzer AllocationSize.QuadPart = SafeInitialSize.QuadPart + PAGE_SIZE; 5352969c28aSPierre Schweitzer 5362969c28aSPierre Schweitzer /* First, attempt to replace the page file, if existing */ 537c2c66affSColin Finck Status = IoCreateFile(&FileHandle, 5382969c28aSPierre Schweitzer SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA, 539c2c66affSColin Finck &ObjectAttributes, 540c2c66affSColin Finck &IoStatus, 5412969c28aSPierre Schweitzer &AllocationSize, 5422969c28aSPierre Schweitzer FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 5432969c28aSPierre Schweitzer FILE_SHARE_WRITE, 5442969c28aSPierre Schweitzer FILE_SUPERSEDE, 5452969c28aSPierre Schweitzer FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 546c2c66affSColin Finck NULL, 547c2c66affSColin Finck 0, 548c2c66affSColin Finck CreateFileTypeNone, 549c2c66affSColin Finck NULL, 550c2c66affSColin Finck SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 5512969c28aSPierre Schweitzer /* If we failed, relax a bit constraints, someone may be already holding the 5522969c28aSPierre Schweitzer * the file, so share write, don't attempt to replace and don't delete on close 5532969c28aSPierre Schweitzer * (basically, don't do anything conflicting) 5542969c28aSPierre Schweitzer */ 5552969c28aSPierre Schweitzer if (!NT_SUCCESS(Status)) 5562969c28aSPierre Schweitzer { 5572969c28aSPierre Schweitzer Status = IoCreateFile(&FileHandle, 5582969c28aSPierre Schweitzer SYNCHRONIZE | FILE_WRITE_DATA, 5592969c28aSPierre Schweitzer &ObjectAttributes, 5602969c28aSPierre Schweitzer &IoStatus, 5612969c28aSPierre Schweitzer &AllocationSize, 5622969c28aSPierre Schweitzer FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 5632969c28aSPierre Schweitzer FILE_SHARE_WRITE | FILE_SHARE_READ, 5642969c28aSPierre Schweitzer FILE_OPEN, 5652969c28aSPierre Schweitzer FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING, 5662969c28aSPierre Schweitzer NULL, 5672969c28aSPierre Schweitzer 0, 5682969c28aSPierre Schweitzer CreateFileTypeNone, 5692969c28aSPierre Schweitzer NULL, 5702969c28aSPierre Schweitzer SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 5712969c28aSPierre Schweitzer } 572c2c66affSColin Finck 573c2c66affSColin Finck ReleaseCapturedUnicodeString(&CapturedFileName, 574c2c66affSColin Finck PreviousMode); 575c2c66affSColin Finck if (!NT_SUCCESS(Status)) 576c2c66affSColin Finck { 5772969c28aSPierre Schweitzer DPRINT1("Failed creating page file: %lx\n", Status); 57828b4b419SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 579c2c66affSColin Finck return(Status); 580c2c66affSColin Finck } 581c2c66affSColin Finck 58228b4b419SPierre Schweitzer /* Set the security descriptor */ 58328b4b419SPierre Schweitzer if (NT_SUCCESS(IoStatus.Status)) 58428b4b419SPierre Schweitzer { 58528b4b419SPierre Schweitzer Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor); 58628b4b419SPierre Schweitzer if (!NT_SUCCESS(Status)) 58728b4b419SPierre Schweitzer { 58828b4b419SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 58928b4b419SPierre Schweitzer ZwClose(FileHandle); 59028b4b419SPierre Schweitzer return Status; 59128b4b419SPierre Schweitzer } 59228b4b419SPierre Schweitzer } 59328b4b419SPierre Schweitzer 59428b4b419SPierre Schweitzer /* DACL is no longer needed, free it */ 59528b4b419SPierre Schweitzer ExFreePoolWithTag(Dacl, 'lcaD'); 59628b4b419SPierre Schweitzer 5972969c28aSPierre Schweitzer /* Set its end of file to initial size */ 598c2c66affSColin Finck Status = ZwSetInformationFile(FileHandle, 599c2c66affSColin Finck &IoStatus, 600c2c66affSColin Finck &SafeInitialSize, 601c2c66affSColin Finck sizeof(LARGE_INTEGER), 6022969c28aSPierre Schweitzer FileEndOfFileInformation); 6032969c28aSPierre Schweitzer if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status)) 604c2c66affSColin Finck { 605c2c66affSColin Finck ZwClose(FileHandle); 606c2c66affSColin Finck return(Status); 607c2c66affSColin Finck } 608c2c66affSColin Finck 609c2c66affSColin Finck Status = ObReferenceObjectByHandle(FileHandle, 610c2c66affSColin Finck FILE_ALL_ACCESS, 611c2c66affSColin Finck IoFileObjectType, 612c2c66affSColin Finck KernelMode, 613c2c66affSColin Finck (PVOID*)&FileObject, 614c2c66affSColin Finck NULL); 615c2c66affSColin Finck if (!NT_SUCCESS(Status)) 616c2c66affSColin Finck { 617c2c66affSColin Finck ZwClose(FileHandle); 618c2c66affSColin Finck return(Status); 619c2c66affSColin Finck } 620c2c66affSColin Finck 62136c20dc5SPierre Schweitzer /* Deny page file creation on a floppy disk */ 62236c20dc5SPierre Schweitzer FsDeviceInfo.Characteristics = 0; 62336c20dc5SPierre Schweitzer IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count); 62436c20dc5SPierre Schweitzer if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE)) 62536c20dc5SPierre Schweitzer { 62636c20dc5SPierre Schweitzer ObDereferenceObject(FileObject); 62736c20dc5SPierre Schweitzer ZwClose(FileHandle); 62836c20dc5SPierre Schweitzer return STATUS_FLOPPY_VOLUME; 62936c20dc5SPierre Schweitzer } 63036c20dc5SPierre Schweitzer 631c2c66affSColin Finck PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile)); 632c2c66affSColin Finck if (PagingFile == NULL) 633c2c66affSColin Finck { 634c2c66affSColin Finck ObDereferenceObject(FileObject); 635c2c66affSColin Finck ZwClose(FileHandle); 636c2c66affSColin Finck return(STATUS_NO_MEMORY); 637c2c66affSColin Finck } 638c2c66affSColin Finck 639c2c66affSColin Finck RtlZeroMemory(PagingFile, sizeof(*PagingFile)); 640c2c66affSColin Finck 6412969c28aSPierre Schweitzer PagingFile->FileHandle = FileHandle; 642c2c66affSColin Finck PagingFile->FileObject = FileObject; 643c2c66affSColin Finck PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart; 644c2c66affSColin Finck PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart; 645c2c66affSColin Finck PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE); 646c2c66affSColin Finck PagingFile->UsedPages = 0; 647c2c66affSColin Finck KeInitializeSpinLock(&PagingFile->AllocMapLock); 648c2c66affSColin Finck 649*f080ee13SPierre Schweitzer AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->FreePages + 31) / 32) * sizeof(ULONG)); 650*f080ee13SPierre Schweitzer PagingFile->AllocMap = ExAllocatePoolWithTag(NonPagedPool, 651*f080ee13SPierre Schweitzer AllocMapSize, 652*f080ee13SPierre Schweitzer TAG_MM); 653c2c66affSColin Finck if (PagingFile->AllocMap == NULL) 654c2c66affSColin Finck { 655c2c66affSColin Finck ExFreePool(PagingFile); 656c2c66affSColin Finck ObDereferenceObject(FileObject); 657c2c66affSColin Finck ZwClose(FileHandle); 658c2c66affSColin Finck return(STATUS_NO_MEMORY); 659c2c66affSColin Finck } 660c2c66affSColin Finck 661*f080ee13SPierre Schweitzer RtlInitializeBitMap(PagingFile->AllocMap, 662*f080ee13SPierre Schweitzer (PULONG)(PagingFile->AllocMap + 1), 663*f080ee13SPierre Schweitzer (ULONG)(PagingFile->FreePages)); 664*f080ee13SPierre Schweitzer RtlClearAllBits(PagingFile->AllocMap); 665c2c66affSColin Finck 666c2c66affSColin Finck KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 667c2c66affSColin Finck for (i = 0; i < MAX_PAGING_FILES; i++) 668c2c66affSColin Finck { 669c2c66affSColin Finck if (PagingFileList[i] == NULL) 670c2c66affSColin Finck { 671c2c66affSColin Finck PagingFileList[i] = PagingFile; 672c2c66affSColin Finck break; 673c2c66affSColin Finck } 674c2c66affSColin Finck } 675c2c66affSColin Finck MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages; 676c2c66affSColin Finck MmNumberOfPagingFiles++; 677c2c66affSColin Finck KeReleaseSpinLock(&PagingFileListLock, oldIrql); 678c2c66affSColin Finck 679c2c66affSColin Finck MmSwapSpaceMessage = FALSE; 680c2c66affSColin Finck 681c2c66affSColin Finck return(STATUS_SUCCESS); 682c2c66affSColin Finck } 683c2c66affSColin Finck 684c2c66affSColin Finck /* EOF */ 685