From 383eddd11ed916a9e616beb2ba39a88c2af13a19 Mon Sep 17 00:00:00 2001 From: David Welch Date: Sat, 10 Aug 2002 16:41:20 +0000 Subject: [PATCH] 2002-08-10 David Welch * ntoskrnl/mm/i386/page.c (MmSetPageProtect): Fixed behaviour when called on the system address space. 2002-08-10 David Welch * ntoskrnl/mm/virtual.c (MmQueryAnonMem, MmProtectAnonMem, NtAllocateVirtualMemory, NtFreeVirtualMemory): Renamed segments to regions; moved region code to seperate file. Implemented NtQueryVirtualMemory and NtProtectVirtualMemory for anonymous memory areas. 2002-08-10 David Welch * ntoskrnl/mm/anonmem.c: Moved functions relating to areas created with NtAllocateVirtualMemory to a seperate file. 2002-08-10 David Welch * ntoskrnl/mm/section.c (MmQuerySectionView): Implemented NtQueryVirtualMemory for section views. 2002-08-10 David Welch * ntoskrnl/mm/section.c (MmAccessFaultSectionView, MmNotPresentFaultSectionView, MmProtectSectionView, MmMapViewOfSegment, MmAlterViewAttributes): Implemented NtProtectVirtualMemory for section views. 2002-08-10 David Welch * ntoskrnl/ke/main.c: Removed SEH test code. 2002-08-10 David Welch * lib/ntdll/ldr/utils.c (LdrFixupImports): Remove the readonly protection from the IAT before writing to it. 2002-08-10 David Welch * lib/ntdll/ldr/utils.c (LdrAdjustDllName): Properly null terminate the base name of the DLL. 2002-08-10 David Welch * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set the text segment of modules to readonly after loading. svn path=/trunk/; revision=3327 --- reactos/ChangeLog | 50 + reactos/lib/ntdll/ldr/utils.c | 47 +- reactos/ntoskrnl/Makefile | 6 +- reactos/ntoskrnl/include/internal/mm.h | 63 +- reactos/ntoskrnl/ke/main.c | 190 +-- reactos/ntoskrnl/ldr/loader.c | 27 +- reactos/ntoskrnl/mm/anonmem.c | 809 ++++++++++++ reactos/ntoskrnl/mm/i386/page.c | 6 +- reactos/ntoskrnl/mm/mm.c | 9 +- reactos/ntoskrnl/mm/pageop.c | 12 +- reactos/ntoskrnl/mm/region.c | 303 +++++ reactos/ntoskrnl/mm/rmap.c | 4 +- reactos/ntoskrnl/mm/section.c | 199 ++- reactos/ntoskrnl/mm/virtual.c | 1575 +++--------------------- reactos/ntoskrnl/rtl/seh.c | 13 + reactos/test.commit | 3 - 16 files changed, 1670 insertions(+), 1646 deletions(-) create mode 100644 reactos/ntoskrnl/mm/anonmem.c create mode 100644 reactos/ntoskrnl/mm/region.c delete mode 100644 reactos/test.commit diff --git a/reactos/ChangeLog b/reactos/ChangeLog index 2fab6fc71aa..837ee9fad62 100644 --- a/reactos/ChangeLog +++ b/reactos/ChangeLog @@ -1,3 +1,53 @@ +2002-08-10 David Welch + + * ntoskrnl/mm/i386/page.c (MmSetPageProtect): Fixed + behaviour when called on the system address space. + +2002-08-10 David Welch + + * ntoskrnl/mm/virtual.c (MmQueryAnonMem, MmProtectAnonMem, + NtAllocateVirtualMemory, NtFreeVirtualMemory): Renamed + segments to regions; moved region code to seperate file. + Implemented NtQueryVirtualMemory and NtProtectVirtualMemory + for anonymous memory areas. + +2002-08-10 David Welch + + * ntoskrnl/mm/anonmem.c: Moved functions relating to + areas created with NtAllocateVirtualMemory to a + seperate file. + +2002-08-10 David Welch + + * ntoskrnl/mm/section.c (MmQuerySectionView): Implemented + NtQueryVirtualMemory for section views. + +2002-08-10 David Welch + + * ntoskrnl/mm/section.c (MmAccessFaultSectionView, + MmNotPresentFaultSectionView, MmProtectSectionView, + MmMapViewOfSegment, MmAlterViewAttributes): Implemented + NtProtectVirtualMemory for section views. + +2002-08-10 David Welch + + * ntoskrnl/ke/main.c: Removed SEH test code. + +2002-08-10 David Welch + + * lib/ntdll/ldr/utils.c (LdrFixupImports): Remove the readonly + protection from the IAT before writing to it. + +2002-08-10 David Welch + + * lib/ntdll/ldr/utils.c (LdrAdjustDllName): Properly null terminate + the base name of the DLL. + +2002-08-10 David Welch + + * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set the text segment + of modules to readonly after loading. + 2002-08-09 David Welch * ntoskrnl/ps/create.c (NtCreateThread): Call PsSuspendThread diff --git a/reactos/lib/ntdll/ldr/utils.c b/reactos/lib/ntdll/ldr/utils.c index 6c7bec80a23..fb7e1aec9c6 100644 --- a/reactos/lib/ntdll/ldr/utils.c +++ b/reactos/lib/ntdll/ldr/utils.c @@ -1,4 +1,4 @@ -/* $Id: utils.c,v 1.52 2002/08/08 17:54:13 dwelch Exp $ +/* $Id: utils.c,v 1.53 2002/08/10 16:41:17 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -112,11 +112,13 @@ LdrAdjustDllName (PUNICODE_STRING FullDllName, Pointer++; Length = Extension - Pointer; memmove (Buffer, Pointer, Length * sizeof(WCHAR)); + Buffer[Length] = L'\0'; } else { /* get the full dll name */ memmove (Buffer, DllName->Buffer, DllName->Length); + Buffer[DllName->Length / sizeof(WCHAR)] = L'\0'; } /* Build the DLL's absolute name */ @@ -941,6 +943,7 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders, ULONG Ordinal; PVOID BaseAddress; NTSTATUS Status; + ULONG IATSize; DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders, ImageBase); @@ -961,6 +964,8 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders, UNICODE_STRING DllName; DWORD pName; WORD pHint; + PVOID IATBase; + ULONG OldProtect; DPRINT("ImportModule->Directory->dwRVAModuleName %s\n", (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName)); @@ -1008,6 +1013,31 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders, (PULONG)(ImageBase + ImportModuleDirectory->dwRVAFunctionAddressList); } + + /* + * Get the size of IAT. + */ + IATSize = 0; + while (FunctionNameList[IATSize] != 0L) + { + IATSize++; + } + + /* + * Unprotect the region we are about to write into. + */ + IATBase = (PVOID)ImportAddressList; + Status = NtProtectVirtualMemory(NtCurrentProcess(), + IATBase, + IATSize * sizeof(PVOID*), + PAGE_READWRITE, + &OldProtect); + if (!NT_SUCCESS(Status)) + { + DbgPrint("LDR: Failed to unprotect IAT.\n"); + return(Status); + } + /* * Walk through function list and fixup addresses. */ @@ -1036,6 +1066,21 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders, ImportAddressList++; FunctionNameList++; } + + /* + * Protect the region we are about to write into. + */ + Status = NtProtectVirtualMemory(NtCurrentProcess(), + IATBase, + IATSize * sizeof(PVOID*), + OldProtect, + &OldProtect); + if (!NT_SUCCESS(Status)) + { + DbgPrint("LDR: Failed to protect IAT.\n"); + return(Status); + } + ImportModuleDirectory++; } return STATUS_SUCCESS; diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index dc38787ee41..b25b7781a2e 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.78 2002/07/25 13:18:31 ekohl Exp $ +# $Id: Makefile,v 1.79 2002/08/10 16:41:17 dwelch Exp $ # # ReactOS Operating System # @@ -158,7 +158,9 @@ OBJECTS_MM = \ mm/pageop.o \ mm/balance.o \ mm/rmap.o \ - mm/slab.o + mm/slab.o \ + mm/anonmem.o \ + mm/region.o # I/O Subsystem (Io) OBJECTS_IO = \ diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index f795ceef4ab..39dd903e429 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -17,19 +17,17 @@ struct _MM_PAGEOP; typedef ULONG SWAPENTRY; #define MEMORY_AREA_INVALID (0) -#define MEMORY_AREA_SECTION_VIEW_COMMIT (1) +#define MEMORY_AREA_SECTION_VIEW (1) #define MEMORY_AREA_CONTINUOUS_MEMORY (2) #define MEMORY_AREA_NO_CACHE (3) #define MEMORY_AREA_IO_MAPPING (4) #define MEMORY_AREA_SYSTEM (5) #define MEMORY_AREA_MDL_MAPPING (7) #define MEMORY_AREA_VIRTUAL_MEMORY (8) -#define MEMORY_AREA_SECTION_VIEW_RESERVE (9) -#define MEMORY_AREA_CACHE_SEGMENT (10) -#define MEMORY_AREA_SHARED_DATA (11) -#define MEMORY_AREA_WORKING_SET (12) -#define MEMORY_AREA_KERNEL_STACK (13) -#define MEMORY_AREA_PAGED_POOL (14) +#define MEMORY_AREA_CACHE_SEGMENT (9) +#define MEMORY_AREA_SHARED_DATA (10) +#define MEMORY_AREA_KERNEL_STACK (11) +#define MEMORY_AREA_PAGED_POOL (12) #define PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(x) \ ((x) / (4*1024*1024)) @@ -137,10 +135,11 @@ typedef struct LIST_ENTRY ViewListEntry; PMM_SECTION_SEGMENT Segment; BOOLEAN WriteCopyView; + LIST_ENTRY RegionListHead; } SectionData; struct { - LIST_ENTRY SegmentListHead; + LIST_ENTRY RegionListHead; } VirtualMemoryData; } Data; } MEMORY_AREA, *PMEMORY_AREA; @@ -547,4 +546,52 @@ MmDumpToPagingFile(ULONG BugCode, ULONG BugCodeParameter4, struct _KTRAP_FRAME* TrapFrame); +typedef VOID (*PMM_ALTER_REGION_FUNC)(PMADDRESS_SPACE AddressSpace, + PVOID BaseAddress, ULONG Length, + ULONG OldType, ULONG OldProtect, + ULONG NewType, ULONG NewProtect); + +typedef struct _MM_REGION +{ + ULONG Type; + ULONG Protect; + ULONG Length; + LIST_ENTRY RegionListEntry; +} MM_REGION, *PMM_REGION; + +NTSTATUS +MmAlterRegion(PMADDRESS_SPACE AddressSpace, PVOID BaseAddress, + PLIST_ENTRY RegionListHead, PVOID StartAddress, ULONG Length, + ULONG NewType, ULONG NewProtect, + PMM_ALTER_REGION_FUNC AlterFunc); +VOID +MmInitialiseRegion(PLIST_ENTRY RegionListHead, ULONG Length, ULONG Type, + ULONG Protect); +PMM_REGION +MmFindRegion(PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, + PVOID* RegionBaseAddress); +NTSTATUS STDCALL +MmQueryAnonMem(PMEMORY_AREA MemoryArea, + PVOID Address, + PMEMORY_BASIC_INFORMATION Info, + PULONG ResultLength); +NTSTATUS STDCALL +MmQuerySectionView(PMEMORY_AREA MemoryArea, + PVOID Address, + PMEMORY_BASIC_INFORMATION Info, + PULONG ResultLength); +NTSTATUS +MmProtectAnonMem(PMADDRESS_SPACE AddressSpace, + PMEMORY_AREA MemoryArea, + PVOID BaseAddress, + ULONG Length, + ULONG Protect, + PULONG OldProtect); +NTSTATUS +MmProtectSectionView(PMADDRESS_SPACE AddressSpace, + PMEMORY_AREA MemoryArea, + PVOID BaseAddress, + ULONG Length, + ULONG Protect, + PULONG OldProtect); #endif diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index 674bdd01a7e..966091553ca 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: main.c,v 1.132 2002/07/29 15:27:59 ekohl Exp $ +/* $Id: main.c,v 1.133 2002/08/10 16:41:18 dwelch Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/main.c @@ -282,194 +282,6 @@ InitSystemSharedUserPage (PCSZ ParameterLine) } } -#ifndef NDEBUG - -VOID DumpBIOSMemoryMap(VOID) -{ - ULONG i; - - DbgPrint("Dumping BIOS memory map:\n"); - DbgPrint("Memory map base: %d\n", KeLoaderBlock.MmapAddr); - DbgPrint("Memory map size: %d\n", KeLoaderBlock.MmapLength); - DbgPrint("Address range count: %d\n", KeMemoryMapRangeCount); - for (i = 0; i < KeMemoryMapRangeCount; i++) - { - DbgPrint("Range: Base (%08X) Length (%08X) Type (%02X)\n", - KeMemoryMap[i].BaseAddrLow, - KeMemoryMap[i].LengthLow, - KeMemoryMap[i].Type); - } - for (;;); -} - -#endif /* !NDEBUG */ - -#if 1 -// SEH Test - -static ULONG Scratch; - -EXCEPTION_DISPOSITION -ExpUnhandledException1( - PEXCEPTION_RECORD ExceptionRecord, - PEXCEPTION_REGISTRATION ExceptionRegistration, - PCONTEXT Context, - PVOID DispatcherContext) -{ - DbgPrint("ExpUnhandledException1() called\n"); - DbgPrint("ExceptionRecord 0x%X\n", ExceptionRecord); - DbgPrint(" Flags 0x%X\n", ExceptionRecord->ExceptionFlags); - DbgPrint("ExceptionRegistration 0x%X\n", ExceptionRegistration); - DbgPrint("Context 0x%X\n", Context); - DbgPrint("DispatcherContext 0x%X\n", DispatcherContext); - - Context->Eax = (ULONG)&Scratch; - - return ExceptionContinueExecution; -} - - -EXCEPTION_DISPOSITION -ExpUnhandledException2( - PEXCEPTION_RECORD ExceptionRecord, - PEXCEPTION_REGISTRATION ExceptionRegistration, - PCONTEXT Context, - PVOID DispatcherContext) -{ - DbgPrint("ExpUnhandledException2() called\n"); - DbgPrint("ExceptionRecord 0x%X\n", ExceptionRecord); - DbgPrint(" Flags 0x%X\n", ExceptionRecord->ExceptionFlags); - DbgPrint("ExceptionRegistration 0x%X\n", ExceptionRegistration); - DbgPrint("Context 0x%X\n", Context); - DbgPrint("DispatcherContext 0x%X\n", DispatcherContext); - -#if 1 - Context->Eax = (ULONG)&Scratch; - - return ExceptionContinueExecution; - -#else - - return ExceptionContinueSearch; - -#endif -} - - -#if 1 -// Put in mingw headers -extern VOID -CDECL -_local_unwind2( - PEXCEPTION_REGISTRATION RegistrationFrame, - DWORD TryLevel); - -extern VOID -CDECL -_global_unwind2( - PVOID RegistrationFrame); - -extern EXCEPTION_DISPOSITION -CDECL -_except_handler2( - PEXCEPTION_RECORD ExceptionRecord, - PEXCEPTION_REGISTRATION RegistrationFrame, - PCONTEXT Context, - PVOID DispatcherContext); - -extern EXCEPTION_DISPOSITION -CDECL -_except_handler3( - PEXCEPTION_RECORD ExceptionRecord, - PEXCEPTION_REGISTRATION RegistrationFrame, - PCONTEXT Context, - PVOID DispatcherContext); - -#endif - -PRTL_EXCEPTION_REGISTRATION -CurrentRER(VOID) -{ - ULONG Value; - - __asm__("movl %%ebp, %0\n\t" : "=a" (Value)); - - return((PRTL_EXCEPTION_REGISTRATION)Value) - 1; -} - -PULONG x; -PRTL_EXCEPTION_REGISTRATION TestER; -SCOPETABLE_ENTRY ScopeTable; -PEXCEPTION_REGISTRATION OSPtr; - - -DWORD CDECL SEHFilterRoutine(VOID) -{ - DbgPrint("Within filter routine.\n"); - return EXCEPTION_EXECUTE_HANDLER; - //return EXCEPTION_CONTINUE_EXECUTION; -} - -VOID CDECL SEHHandlerRoutine(VOID) -{ - DbgPrint("Within exception handler.\n"); - DbgPrint("System halted.\n"); - for (;;); -} - - -VOID SEHTest() -{ - RTL_EXCEPTION_REGISTRATION ER; - LPEXCEPTION_POINTERS ExceptionPointers; - PVOID StandardESPInFrame; - - __asm__ ("movl %%esp,%%eax;" : "=a" (StandardESPInFrame)); - DbgPrint("StandardESPInFrame: 0x%X\n", StandardESPInFrame); - - ExceptionPointers = NULL; - - ER.OS.handler = _except_handler3; - __asm__ ("movl %%fs:0,%%eax;" : "=a" (ER.OS.prev)); - DbgPrint("ER.OS.prev: 0x%X\n", ER.OS.prev); - - ER.ScopeTable = &ScopeTable; - DbgPrint("ER.ScopeTable: 0x%X\n", ER.ScopeTable); - ER.TryLevel = -1; - __asm__ ("movl %%ebp,%%eax;" : "=a" (ER.Ebp)); - DbgPrint("ER.Ebp: 0x%X\n", ER.Ebp); - - ScopeTable.PreviousTryLevel = -1; - ScopeTable.FilterRoutine = SEHFilterRoutine; - DbgPrint("ScopeTable.FilterRoutine: 0x%X\n", ScopeTable.FilterRoutine); - ScopeTable.HandlerRoutine = SEHHandlerRoutine; - DbgPrint("ScopeTable.HandlerRoutine: 0x%X\n", ScopeTable.HandlerRoutine); - - - OSPtr = &ER.OS; - DbgPrint("OSPtr: 0x%X\n", OSPtr); - - __asm__ ("movl %0,%%eax;movl %%eax,%%fs:0;" : : "m" (OSPtr)); - - /*__try1(__except_handler3)*/ if(1) { - ER.TryLevel = 0; // Entered first try... block - - DbgPrint("Within guarded section.\n"); - x = (PULONG)0xf2000000; *x = 0; - DbgPrint("After exception.\n"); - } /* __except1 */ if(0) { - } - - DbgPrint("After exception2.\n"); - - __asm__ ("movl %0,%%eax;movl %%eax,%%fs:0;" : : "m" (ER.OS.prev)); - //KeGetCurrentKPCR()->ExceptionList = ER.OS.prev; - - DbgPrint("Exiting.\n"); -} - -#endif - VOID ExpInitializeExecutive(VOID) { diff --git a/reactos/ntoskrnl/ldr/loader.c b/reactos/ntoskrnl/ldr/loader.c index 3652c06874d..ca95a5cd7a7 100644 --- a/reactos/ntoskrnl/ldr/loader.c +++ b/reactos/ntoskrnl/ldr/loader.c @@ -1,4 +1,4 @@ -/* $Id: loader.c,v 1.118 2002/07/18 00:25:31 dwelch Exp $ +/* $Id: loader.c,v 1.119 2002/08/10 16:41:18 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef HALDBG #include @@ -1098,6 +1099,30 @@ LdrPEProcessModule(PVOID ModuleLoadBase, } } + /* Set the protections for the various parts of the driver */ + for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++) + { + ULONG Characteristics = PESectionHeaders[Idx].Characteristics; + ULONG Length; + PVOID BaseAddress; + ULONG i; + Length = + max(PESectionHeaders[Idx].Misc.VirtualSize, + PESectionHeaders[Idx].SizeOfRawData); + BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase; + if (Characteristics & IMAGE_SECTION_CHAR_CODE && + !(Characteristics & IMAGE_SECTION_CHAR_WRITABLE || + Characteristics & IMAGE_SECTION_CHAR_DATA || + Characteristics & IMAGE_SECTION_CHAR_BSS)) + { + for (i = 0; i < PAGE_ROUND_DOWN(Length); i++) + { + MmSetPageProtect(NULL, BaseAddress + (i * PAGESIZE), + PAGE_READONLY); + } + } + } + /* Create the module */ CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT)); if (CreatedModuleObject == NULL) diff --git a/reactos/ntoskrnl/mm/anonmem.c b/reactos/ntoskrnl/mm/anonmem.c new file mode 100644 index 00000000000..d9e5612dfc8 --- /dev/null +++ b/reactos/ntoskrnl/mm/anonmem.c @@ -0,0 +1,809 @@ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: anonmem.c,v 1.1 2002/08/10 16:41:19 dwelch Exp $ + * + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/mm/anonmem.c + * PURPOSE: Implementing anonymous memory. + * PROGRAMMER: David Welch + */ + +/* INCLUDE *****************************************************************/ + +#include +#include +#include +#include +#include +#include + +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace, + PMEMORY_AREA MArea, + PVOID Address) +{ + return(STATUS_UNSUCCESSFUL); +} + + +NTSTATUS +MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace, + PMEMORY_AREA MemoryArea, + PVOID Address, + PMM_PAGEOP PageOp) +{ + PHYSICAL_ADDRESS PhysicalAddress; + BOOL WasDirty; + SWAPENTRY SwapEntry; + NTSTATUS Status; + PMDL Mdl; + + DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n", + Address, MemoryArea->Process->UniqueProcessId); + + /* + * Check for paging out from a deleted virtual memory area. + */ + if (MemoryArea->DeleteInProgress) + { + return(STATUS_UNSUCCESSFUL); + } + + /* + * Paging out code or readonly data is easy. + */ + if ((MemoryArea->Attributes & PAGE_READONLY) || + (MemoryArea->Attributes & PAGE_EXECUTE_READ)) + { + MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, + NULL, &PhysicalAddress); + MmDeleteAllRmaps(PhysicalAddress, NULL, NULL); + if (MmGetSavedSwapEntryPage(PhysicalAddress) != 0) + { + DPRINT1("Read-only page was swapped out.\n"); + KeBugCheck(0); + } + MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); + + PageOp->Status = STATUS_SUCCESS; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + return(STATUS_SUCCESS); + } + + /* + * Otherwise this is read-write data + */ + MmDisableVirtualMapping(MemoryArea->Process, Address, + &WasDirty, (PULONG)&PhysicalAddress); + if (PhysicalAddress.QuadPart == 0) + { + KeBugCheck(0); + } + if (!WasDirty) + { + MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL); + MmDeleteAllRmaps(PhysicalAddress, NULL, NULL); + if ((SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress)) != 0) + { + MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry); + MmSetSavedSwapEntryPage(PhysicalAddress, 0); + } + MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); + PageOp->Status = STATUS_SUCCESS; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + return(STATUS_SUCCESS); + } + + /* + * If necessary, allocate an entry in the paging file for this page + */ + SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress); + if (SwapEntry == 0) + { + SwapEntry = MmAllocSwapPage(); + if (SwapEntry == 0) + { + MmEnableVirtualMapping(MemoryArea->Process, Address); + PageOp->Status = STATUS_UNSUCCESSFUL; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + return(STATUS_UNSUCCESSFUL); + } + } + + /* + * Write the page to the pagefile + */ + Mdl = MmCreateMdl(NULL, NULL, PAGESIZE); + MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress); + Status = MmWriteToSwapPage(SwapEntry, Mdl); + if (!NT_SUCCESS(Status)) + { + DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", + Status); + MmEnableVirtualMapping(MemoryArea->Process, Address); + PageOp->Status = STATUS_UNSUCCESSFUL; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + return(STATUS_UNSUCCESSFUL); + } + + /* + * Otherwise we have succeeded, free the page + */ + DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", PhysicalAddress); + MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL); + MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry); + MmDeleteAllRmaps(PhysicalAddress, NULL, NULL); + MmSetSavedSwapEntryPage(PhysicalAddress, 0); + MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); + PageOp->Status = STATUS_SUCCESS; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + return(STATUS_SUCCESS); +} + +NTSTATUS +MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace, + MEMORY_AREA* MemoryArea, + PVOID Address, + BOOLEAN Locked) +/* + * FUNCTION: Move data into memory to satisfy a page not present fault + * ARGUMENTS: + * AddressSpace = Address space within which the fault occurred + * MemoryArea = The memory area within which the fault occurred + * Address = The absolute address of fault + * RETURNS: Status + * NOTES: This function is called with the address space lock held. + */ +{ + PHYSICAL_ADDRESS Page; + NTSTATUS Status; + PMM_REGION Region; + PMM_PAGEOP PageOp; + + /* + * There is a window between taking the page fault and locking the + * address space when another thread could load the page so we check + * that. + */ + if (MmIsPagePresent(NULL, Address)) + { + if (Locked) + { + MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + } + return(STATUS_SUCCESS); + } + + /* + * Check for the virtual memory area being deleted. + */ + if (MemoryArea->DeleteInProgress) + { + return(STATUS_UNSUCCESSFUL); + } + + /* + * Get the segment corresponding to the virtual address + */ + Region = MmFindRegion(MemoryArea->BaseAddress, + &MemoryArea->Data.VirtualMemoryData.RegionListHead, + Address, NULL); + if (Region->Type == MEM_RESERVE) + { + return(STATUS_UNSUCCESSFUL); + } + + /* + * Get or create a page operation + */ + PageOp = MmGetPageOp(MemoryArea, (ULONG)PsGetCurrentProcessId(), + (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0, + MM_PAGEOP_PAGEIN); + if (PageOp == NULL) + { + DPRINT1("MmGetPageOp failed"); + KeBugCheck(0); + } + + /* + * Check if someone else is already handling this fault, if so wait + * for them + */ + if (PageOp->Thread != PsGetCurrentThread()) + { + MmUnlockAddressSpace(AddressSpace); + Status = KeWaitForSingleObject(&PageOp->CompletionEvent, + 0, + KernelMode, + FALSE, + NULL); + /* + * Check for various strange conditions + */ + if (Status != STATUS_SUCCESS) + { + DPRINT1("Failed to wait for page op\n"); + KeBugCheck(0); + } + if (PageOp->Status == STATUS_PENDING) + { + DPRINT1("Woke for page op before completion\n"); + KeBugCheck(0); + } + /* + * If this wasn't a pagein then we need to restart the handling + */ + if (PageOp->OpType != MM_PAGEOP_PAGEIN) + { + MmLockAddressSpace(AddressSpace); + MmReleasePageOp(PageOp); + return(STATUS_MM_RESTART_OPERATION); + } + /* + * If the thread handling this fault has failed then we don't retry + */ + if (!NT_SUCCESS(PageOp->Status)) + { + MmLockAddressSpace(AddressSpace); + MmReleasePageOp(PageOp); + return(Status); + } + MmLockAddressSpace(AddressSpace); + if (Locked) + { + MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + } + MmReleasePageOp(PageOp); + return(STATUS_SUCCESS); + } + + /* + * Try to allocate a page + */ + Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page); + if (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); + MmLockAddressSpace(AddressSpace); + } + + /* + * Handle swapped out pages. + */ + if (MmIsPageSwapEntry(NULL, Address)) + { + SWAPENTRY SwapEntry; + PMDL Mdl; + + MmDeletePageFileMapping(NULL, Address, &SwapEntry); + Mdl = MmCreateMdl(NULL, NULL, PAGESIZE); + MmBuildMdlFromPages(Mdl, (PULONG)&Page); + Status = MmReadFromSwapPage(SwapEntry, Mdl); + if (!NT_SUCCESS(Status)) + { + KeBugCheck(0); + } + MmSetSavedSwapEntryPage(Page, SwapEntry); + } + + /* + * Set the page. If we fail because we are out of memory then + * try again + */ + Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Address, + MemoryArea->Attributes, + Page, + FALSE); + while (Status == STATUS_NO_MEMORY) + { + MmUnlockAddressSpace(AddressSpace); + Status = MmCreateVirtualMapping(PsGetCurrentProcess(), + Address, + MemoryArea->Attributes, + Page, + TRUE); + MmLockAddressSpace(AddressSpace); + } + if (!NT_SUCCESS(Status)) + { + DPRINT1("MmCreateVirtualMapping failed, not out of memory\n"); + KeBugCheck(0); + return(Status); + } + + /* + * Add the page to the process's working set + */ + MmInsertRmap(Page, PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address)); + + /* + * Finish the operation + */ + if (Locked) + { + MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); + } + PageOp->Status = STATUS_SUCCESS; + KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); + MmReleasePageOp(PageOp); + return(STATUS_SUCCESS); +} + +VOID STATIC +MmModifyAttributes(PMADDRESS_SPACE AddressSpace, + PVOID BaseAddress, + ULONG RegionSize, + ULONG OldType, + ULONG OldProtect, + ULONG NewType, + ULONG NewProtect) +/* + * FUNCTION: Modify the attributes of a memory region + */ +{ + /* + * If we are switching a previously committed region to reserved then + * free any allocated pages within the region + */ + if (NewType == MEM_RESERVE && OldType == MEM_COMMIT) + { + ULONG i; + + for (i=0; i <= (RegionSize/PAGESIZE); i++) + { + LARGE_INTEGER PhysicalAddr; + + if (MmIsPageSwapEntry(AddressSpace->Process, + BaseAddress + (i * PAGESIZE))) + { + SWAPENTRY SwapEntry; + + MmDeletePageFileMapping(AddressSpace->Process, + BaseAddress + (i * PAGESIZE), + &SwapEntry); + MmFreeSwapPage(SwapEntry); + } + else + { + PhysicalAddr = MmGetPhysicalAddress(BaseAddress + (i*PAGESIZE)); + MmDeleteVirtualMapping(AddressSpace->Process, + BaseAddress + (i*PAGESIZE), + FALSE, NULL, NULL); + if (PhysicalAddr.QuadPart != 0) + { + MmDeleteRmap(PhysicalAddr, AddressSpace->Process, + BaseAddress + (i * PAGESIZE)); + MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr); + } + } + } + } + + /* + * If we are changing the protection attributes of a committed region then + * alter the attributes for any allocated pages within the region + */ + if (NewType == MEM_COMMIT && OldType == MEM_COMMIT && + OldProtect != NewProtect) + { + ULONG i; + + for (i=0; i <= (RegionSize/PAGESIZE); i++) + { + if (MmIsPagePresent(AddressSpace->Process, + BaseAddress + (i*PAGESIZE))) + { + MmSetPageProtect(AddressSpace->Process, + BaseAddress + (i*PAGESIZE), + NewProtect); + } + } + } +} + +NTSTATUS STDCALL +NtAllocateVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID* UBaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG URegionSize, + IN ULONG AllocationType, + IN ULONG Protect) +/* + * FUNCTION: Allocates a block of virtual memory in the process address space + * ARGUMENTS: + * ProcessHandle = The handle of the process which owns the virtual memory + * BaseAddress = A pointer to the virtual memory allocated. If you + * supply a non zero value the system will try to + * allocate the memory at the address supplied. It round + * it down to a multiple of the page size. + * ZeroBits = (OPTIONAL) You can specify the number of high order bits + * that must be zero, ensuring that the memory will be + * allocated at a address below a certain value. + * RegionSize = The number of bytes to allocate + * AllocationType = Indicates the type of virtual memory you like to + * allocated, can be a combination of MEM_COMMIT, + * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN. + * Protect = Indicates the protection type of the pages allocated, can be + * a combination of PAGE_READONLY, PAGE_READWRITE, + * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD, + * PAGE_NOACCESS + * REMARKS: + * This function maps to the win32 VirtualAllocEx. Virtual memory is + * process based so the protocol starts with a ProcessHandle. I + * splitted the functionality of obtaining the actual address and + * specifying the start address in two parameters ( BaseAddress and + * StartAddress ) The NumberOfBytesAllocated specify the range and the + * AllocationType and ProctectionType map to the other two parameters. + * RETURNS: Status + */ +{ + PEPROCESS Process; + MEMORY_AREA* MemoryArea; + ULONG Type; + NTSTATUS Status; + PMADDRESS_SPACE AddressSpace; + PVOID BaseAddress; + ULONG RegionSize; + PVOID PBaseAddress; + ULONG PRegionSize; + + DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, " + "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n", + *UBaseAddress,ZeroBits,*URegionSize,AllocationType, + Protect); + + /* + * Check the validity of the parameters + */ + if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect) + { + return(STATUS_INVALID_PAGE_PROTECTION); + } + if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0) + { + return(STATUS_INVALID_PARAMETER); + } + + PBaseAddress = *UBaseAddress; + PRegionSize = *URegionSize; + + + BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress); + RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) - + PAGE_ROUND_DOWN(PBaseAddress); + + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_VM_OPERATION, + NULL, + UserMode, + (PVOID*)(&Process), + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtAllocateVirtualMemory() = %x\n",Status); + return(Status); + } + + Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE; + DPRINT("Type %x\n", Type); + + AddressSpace = &Process->AddressSpace; + MmLockAddressSpace(AddressSpace); + + if (PBaseAddress != 0) + { + MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, + BaseAddress); + + if (MemoryArea != NULL && + MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY && + MemoryArea->Length >= RegionSize) + { + Status = + MmAlterRegion(&Process->AddressSpace, + MemoryArea->BaseAddress, + &MemoryArea->Data.VirtualMemoryData.RegionListHead, + PBaseAddress, RegionSize, + Type, Protect, MmModifyAttributes); + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + DPRINT("NtAllocateVirtualMemory() = %x\n",Status); + return(Status); + } + else if (MemoryArea != NULL) + { + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(STATUS_UNSUCCESSFUL); + } + } + + Status = MmCreateMemoryArea(Process, + &Process->AddressSpace, + MEMORY_AREA_VIRTUAL_MEMORY, + &BaseAddress, + RegionSize, + Protect, + &MemoryArea, + PBaseAddress != 0); + + if (!NT_SUCCESS(Status)) + { + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + DPRINT("NtAllocateVirtualMemory() = %x\n",Status); + return(Status); + } + MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead, + RegionSize, Type, Protect); + + if ((AllocationType & MEM_COMMIT) && + ((Protect & PAGE_READWRITE) || + (Protect & PAGE_EXECUTE_READWRITE))) + { + MmReserveSwapPages(RegionSize); + } + + *UBaseAddress = BaseAddress; + *URegionSize = RegionSize; + DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize); + + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(STATUS_SUCCESS); +} + +VOID STATIC +MmFreeVirtualMemoryPage(PVOID Context, + MEMORY_AREA* MemoryArea, + PVOID Address, + PHYSICAL_ADDRESS PhysicalAddr, + SWAPENTRY SwapEntry, + BOOLEAN Dirty) +{ + PEPROCESS Process = (PEPROCESS)Context; + + if (PhysicalAddr.QuadPart != 0) + { + MmDeleteRmap(PhysicalAddr, Process, Address); + MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr); + } + else if (SwapEntry != 0) + { + MmFreeSwapPage(SwapEntry); + } +} + +VOID +MmFreeVirtualMemory(PEPROCESS Process, + PMEMORY_AREA MemoryArea) +{ + PLIST_ENTRY current_entry; + PMM_REGION current; + ULONG i; + + DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process, + MemoryArea); + + /* Mark this memory area as about to be deleted. */ + MemoryArea->DeleteInProgress = TRUE; + + /* + * Wait for any ongoing paging operations. Notice that since we have + * flagged this memory area as deleted no more page ops will be added. + */ + if (MemoryArea->PageOpCount > 0) + { + for (i = 0; i < (PAGE_ROUND_UP(MemoryArea->Length) / PAGESIZE); i++) + { + PMM_PAGEOP PageOp; + + if (MemoryArea->PageOpCount == 0) + { + break; + } + + PageOp = MmCheckForPageOp(MemoryArea, Process->UniqueProcessId, + MemoryArea->BaseAddress + (i * PAGESIZE), + NULL, 0); + if (PageOp != NULL) + { + NTSTATUS Status; + MmUnlockAddressSpace(&Process->AddressSpace); + Status = KeWaitForSingleObject(&PageOp->CompletionEvent, + 0, + KernelMode, + FALSE, + NULL); + if (Status != STATUS_SUCCESS) + { + DPRINT1("Failed to wait for page op\n"); + KeBugCheck(0); + } + MmLockAddressSpace(&Process->AddressSpace); + MmReleasePageOp(PageOp); + } + } + } + + /* Free all the individual segments. */ + current_entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink; + while (current_entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead) + { + current = CONTAINING_RECORD(current_entry, MM_REGION, RegionListEntry); + current_entry = current_entry->Flink; + ExFreePool(current); + } + + /* Actually free the memory area. */ + MmFreeMemoryArea(&Process->AddressSpace, + MemoryArea->BaseAddress, + 0, + MmFreeVirtualMemoryPage, + (PVOID)Process); +} + +NTSTATUS STDCALL +NtFreeVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID* PBaseAddress, + IN PULONG PRegionSize, + IN ULONG FreeType) +/* + * FUNCTION: Frees a range of virtual memory + * ARGUMENTS: + * ProcessHandle = Points to the process that allocated the virtual + * memory + * BaseAddress = Points to the memory address, rounded down to a + * multiple of the pagesize + * RegionSize = Limits the range to free, rounded up to a multiple of + * the paging size + * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE + * RETURNS: Status + */ +{ + MEMORY_AREA* MemoryArea; + NTSTATUS Status; + PEPROCESS Process; + PMADDRESS_SPACE AddressSpace; + PVOID BaseAddress; + ULONG RegionSize; + + DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, " + "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress, + *PRegionSize,FreeType); + + BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress)); + RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) - + PAGE_ROUND_DOWN((*PBaseAddress)); + + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_VM_OPERATION, + PsProcessType, + UserMode, + (PVOID*)(&Process), + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + AddressSpace = &Process->AddressSpace; + + MmLockAddressSpace(AddressSpace); + MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, + BaseAddress); + if (MemoryArea == NULL) + { + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(STATUS_UNSUCCESSFUL); + } + + switch (FreeType) + { + case MEM_RELEASE: + /* We can only free a memory area in one step. */ + if (MemoryArea->BaseAddress != BaseAddress) + { + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(STATUS_UNSUCCESSFUL); + } + MmFreeVirtualMemory(Process, MemoryArea); + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(STATUS_SUCCESS); + + case MEM_DECOMMIT: + Status = + MmAlterRegion(AddressSpace, + MemoryArea->BaseAddress, + &MemoryArea->Data.VirtualMemoryData.RegionListHead, + BaseAddress, + RegionSize, + MEM_RESERVE, + PAGE_NOACCESS, + MmModifyAttributes); + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(Status); + } + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(STATUS_NOT_IMPLEMENTED); +} + +NTSTATUS +MmProtectAnonMem(PMADDRESS_SPACE AddressSpace, + PMEMORY_AREA MemoryArea, + PVOID BaseAddress, + ULONG Length, + ULONG Protect, + PULONG OldProtect) +{ + PMM_REGION Region; + NTSTATUS Status; + + Region = MmFindRegion(MemoryArea->BaseAddress, + &MemoryArea->Data.VirtualMemoryData.RegionListHead, + BaseAddress, NULL); + *OldProtect = Region->Protect; + Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress, + &MemoryArea->Data.VirtualMemoryData.RegionListHead, + BaseAddress, Length, Region->Type, Protect, + MmModifyAttributes); + return(Status); +} + +NTSTATUS STDCALL +MmQueryAnonMem(PMEMORY_AREA MemoryArea, + PVOID Address, + PMEMORY_BASIC_INFORMATION Info, + PULONG ResultLength) +{ + PMM_REGION Region; + PVOID RegionBase; + + Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address); + + Region = MmFindRegion(MemoryArea->BaseAddress, + &MemoryArea->Data.VirtualMemoryData.RegionListHead, + Address, &RegionBase); + Info->AllocationBase = RegionBase; + Info->AllocationProtect = Region->Protect; /* FIXME */ + Info->RegionSize = Region->Length; + Info->State = Region->Type; + Info->Protect = Region->Protect; + Info->Type = MEM_PRIVATE; + return(STATUS_SUCCESS); +} + +/* EOF */ diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c index 530c908dd36..37c06e6d369 100644 --- a/reactos/ntoskrnl/mm/i386/page.c +++ b/reactos/ntoskrnl/mm/i386/page.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: page.c,v 1.38 2002/06/10 21:34:38 hbirr Exp $ +/* $Id: page.c,v 1.39 2002/08/10 16:41:20 dwelch Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/mm/i386/page.c @@ -1082,14 +1082,14 @@ MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) Process, Address, flProtect); Attributes = ProtectToPTE(flProtect); - if (Process != CurrentProcess) + if (Process != NULL && Process != CurrentProcess) { KeAttachProcess(Process); } PageEntry = MmGetPageEntry(Address); (*PageEntry) = PAGE_MASK(*PageEntry) | Attributes; FLUSH_TLB; - if (Process != CurrentProcess) + if (Process != NULL && Process != CurrentProcess) { KeDetachProcess(); } diff --git a/reactos/ntoskrnl/mm/mm.c b/reactos/ntoskrnl/mm/mm.c index 23ed4d71e37..c8d6a8ed77e 100644 --- a/reactos/ntoskrnl/mm/mm.c +++ b/reactos/ntoskrnl/mm/mm.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: mm.c,v 1.57 2002/06/04 15:26:56 dwelch Exp $ +/* $Id: mm.c,v 1.58 2002/08/10 16:41:19 dwelch Exp $ * * COPYRIGHT: See COPYING in the top directory * PROJECT: ReactOS kernel @@ -59,8 +59,7 @@ NTSTATUS MmReleaseMemoryArea(PEPROCESS Process, PMEMORY_AREA Marea) switch (Marea->Type) { - case MEMORY_AREA_SECTION_VIEW_COMMIT: - case MEMORY_AREA_SECTION_VIEW_RESERVE: + case MEMORY_AREA_SECTION_VIEW: Status = MmUnmapViewOfSection(Process, Marea->BaseAddress); assert(Status == STATUS_SUCCESS); return(STATUS_SUCCESS); @@ -214,7 +213,7 @@ NTSTATUS MmAccessFault(KPROCESSOR_MODE Mode, Status = STATUS_SUCCESS; break; - case MEMORY_AREA_SECTION_VIEW_COMMIT: + case MEMORY_AREA_SECTION_VIEW: Status = MmAccessFaultSectionView(AddressSpace, MemoryArea, (PVOID)Address, @@ -346,7 +345,7 @@ NTSTATUS MmNotPresentFault(KPROCESSOR_MODE Mode, Status = STATUS_UNSUCCESSFUL; break; - case MEMORY_AREA_SECTION_VIEW_COMMIT: + case MEMORY_AREA_SECTION_VIEW: Status = MmNotPresentFaultSectionView(AddressSpace, MemoryArea, (PVOID)Address, diff --git a/reactos/ntoskrnl/mm/pageop.c b/reactos/ntoskrnl/mm/pageop.c index 01a99c6be7e..86fa9052689 100644 --- a/reactos/ntoskrnl/mm/pageop.c +++ b/reactos/ntoskrnl/mm/pageop.c @@ -1,4 +1,4 @@ -/* $Id: pageop.c,v 1.10 2002/06/11 22:09:02 dwelch Exp $ +/* $Id: pageop.c,v 1.11 2002/08/10 16:41:19 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -80,7 +80,7 @@ MmCheckForPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address, /* * Calcuate the hash value for pageop structure */ - if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT) + if (MArea->Type == MEMORY_AREA_SECTION_VIEW) { Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGESIZE)); } @@ -98,7 +98,7 @@ MmCheckForPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address, PageOp = MmPageOpHashTable[Hash]; while (PageOp != NULL) { - if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT) + if (MArea->Type == MEMORY_AREA_SECTION_VIEW) { if (PageOp->Segment == Segment && PageOp->Offset == Offset) @@ -147,7 +147,7 @@ MmGetPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address, /* * Calcuate the hash value for pageop structure */ - if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT) + if (MArea->Type == MEMORY_AREA_SECTION_VIEW) { Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGESIZE)); } @@ -165,7 +165,7 @@ MmGetPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address, PageOp = MmPageOpHashTable[Hash]; while (PageOp != NULL) { - if (MArea->Type == MEMORY_AREA_SECTION_VIEW_COMMIT) + if (MArea->Type == MEMORY_AREA_SECTION_VIEW) { if (PageOp->Segment == Segment && PageOp->Offset == Offset) @@ -206,7 +206,7 @@ MmGetPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address, return(NULL); } - if (MArea->Type != MEMORY_AREA_SECTION_VIEW_COMMIT) + if (MArea->Type != MEMORY_AREA_SECTION_VIEW) { PageOp->Pid = Pid; PageOp->Address = Address; diff --git a/reactos/ntoskrnl/mm/region.c b/reactos/ntoskrnl/mm/region.c new file mode 100644 index 00000000000..25cd4c0fb4b --- /dev/null +++ b/reactos/ntoskrnl/mm/region.c @@ -0,0 +1,303 @@ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: region.c,v 1.1 2002/08/10 16:41:19 dwelch Exp $ + * + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/mm/region.c + * PROGRAMMER: David Welch + * PURPOSE: + */ + +/* INCLUDE *****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +#define TAG_MM_REGION TAG('M', 'R', 'G', 'N') + +/* FUNCTIONS *****************************************************************/ + +VOID STATIC +InsertAfterEntry(PLIST_ENTRY Previous, + PLIST_ENTRY Entry) +/* + * FUNCTION: Insert a list entry after another entry in the list + */ +{ + Previous->Flink->Blink = Entry; + + Entry->Flink = Previous->Flink; + Entry->Blink = Previous; + + Previous->Flink = Entry; +} + +PMM_REGION STATIC +MmSplitRegion(PMM_REGION InitialRegion, PVOID InitialBaseAddress, + PVOID StartAddress, ULONG Length, ULONG NewType, + ULONG NewProtect, PMADDRESS_SPACE AddressSpace, + PMM_ALTER_REGION_FUNC AlterFunc) +{ + PMM_REGION NewRegion1; + PMM_REGION NewRegion2; + ULONG InternalLength; + + /* Allocate this in front otherwise the failure case is too difficult. */ + NewRegion2 = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION), + TAG_MM_REGION); + if (NewRegion2 == NULL) + { + return(NULL); + } + + /* Create the new region. */ + NewRegion1 = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION), + TAG_MM_REGION); + if (NewRegion1 == NULL) + { + ExFreePool(NewRegion2); + return(NULL); + } + NewRegion1->Type = NewType; + NewRegion1->Protect = NewProtect; + InternalLength = (InitialBaseAddress + InitialRegion->Length) - StartAddress; + InternalLength = min(InternalLength, Length); + NewRegion1->Length = InternalLength; + InsertAfterEntry(&InitialRegion->RegionListEntry, + &NewRegion1->RegionListEntry); + + /* + * Call our helper function to do the changes on the addresses contained + * in the initial region. + */ + AlterFunc(AddressSpace, StartAddress, InternalLength, InitialRegion->Type, + InitialRegion->Protect, NewType, NewProtect); + + /* + * If necessary create a new region for the portion of the initial region + * beyond the range of addresses to alter. + */ + if ((InitialBaseAddress + InitialRegion->Length) > (StartAddress + Length)) + { + NewRegion2->Type = InitialRegion->Type; + NewRegion2->Protect = InitialRegion->Protect; + NewRegion2->Length = (InitialBaseAddress + InitialRegion->Length) - + (StartAddress + Length); + InsertAfterEntry(&NewRegion1->RegionListEntry, + &NewRegion2->RegionListEntry); + } + else + { + ExFreePool(NewRegion2); + } + + /* Either remove or shrink the initial region. */ + if (InitialBaseAddress == StartAddress) + { + RemoveEntryList(&InitialRegion->RegionListEntry); + ExFreePool(InitialRegion); + } + else + { + InitialRegion->Length = StartAddress - InitialBaseAddress; + } + + return(NewRegion1); +} + +NTSTATUS +MmAlterRegion(PMADDRESS_SPACE AddressSpace, PVOID BaseAddress, + PLIST_ENTRY RegionListHead, PVOID StartAddress, ULONG Length, + ULONG NewType, ULONG NewProtect, PMM_ALTER_REGION_FUNC AlterFunc) +{ + PMM_REGION InitialRegion; + PVOID InitialBaseAddress; + PMM_REGION NewRegion; + PLIST_ENTRY CurrentEntry; + PMM_REGION CurrentRegion; + PVOID CurrentBaseAddress; + ULONG RemainingLength; + + /* + * Find the first region containing part of the range of addresses to + * be altered. + */ + InitialRegion = MmFindRegion(BaseAddress, RegionListHead, StartAddress, + &InitialBaseAddress); + if ((StartAddress + Length) > + (InitialBaseAddress + InitialRegion->Length)) + { + RemainingLength = (StartAddress + Length) - + (InitialBaseAddress + InitialRegion->Length); + } + else + { + RemainingLength = 0; + } + /* + * If necessary then split the region into the affected and unaffected parts. + */ + if (InitialRegion->Type != NewType || InitialRegion->Protect != NewProtect) + { + NewRegion = MmSplitRegion(InitialRegion, InitialBaseAddress, + StartAddress, Length, NewType, NewProtect, + AddressSpace, AlterFunc); + if (NewRegion == NULL) + { + return(STATUS_NO_MEMORY); + } + } + else + { + NewRegion = InitialRegion; + } + + /* + * Free any complete regions that are containing in the range of addresses + * and call the helper function to actually do the changes. + */ + CurrentEntry = NewRegion->RegionListEntry.Flink; + CurrentBaseAddress = StartAddress + NewRegion->Length; + while (RemainingLength > 0 && CurrentRegion->Length <= RemainingLength) + { + CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, + RegionListEntry); + CurrentEntry = CurrentEntry->Flink; + if (CurrentRegion->Type != NewType && + CurrentRegion->Protect != NewProtect) + { + AlterFunc(AddressSpace, CurrentBaseAddress, CurrentRegion->Length, + CurrentRegion->Type, CurrentRegion->Protect, + NewType, NewProtect); + } + CurrentBaseAddress += CurrentRegion->Length; + NewRegion->Length += CurrentRegion->Length; + RemainingLength -= CurrentRegion->Length; + RemoveEntryList(&CurrentRegion->RegionListEntry); + ExFreePool(CurrentRegion); + } + + /* + * Split any final region. + */ + if (RemainingLength > 0) + { + CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, + RegionListEntry); + if (CurrentRegion->Type != NewType && + CurrentRegion->Protect != NewProtect) + { + AlterFunc(AddressSpace, CurrentBaseAddress, CurrentRegion->Length, + CurrentRegion->Type, CurrentRegion->Protect, + NewType, NewProtect); + } + NewRegion->Length += RemainingLength; + CurrentRegion->Length -= RemainingLength; + } + + /* + * If the region after the new region has the same type then merge them. + */ + if (NewRegion->RegionListEntry.Flink != RegionListHead) + { + CurrentEntry = NewRegion->RegionListEntry.Flink; + CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, + RegionListEntry); + if (CurrentRegion->Type == NewRegion->Type && + CurrentRegion->Protect == NewRegion->Protect) + { + NewRegion->Length += CurrentRegion->Length; + RemoveEntryList(&CurrentRegion->RegionListEntry); + ExFreePool(CurrentRegion); + } + } + + /* + * If the region before the new region has the same type then merge them. + */ + if (NewRegion->RegionListEntry.Blink != RegionListHead) + { + CurrentEntry = NewRegion->RegionListEntry.Blink; + CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION, + RegionListEntry); + if (CurrentRegion->Type == NewRegion->Type && + CurrentRegion->Protect == NewRegion->Protect) + { + NewRegion->Length += CurrentRegion->Length; + RemoveEntryList(&CurrentRegion->RegionListEntry); + ExFreePool(CurrentRegion); + } + } + + return(STATUS_SUCCESS); +} + +VOID +MmInitialiseRegion(PLIST_ENTRY RegionListHead, ULONG Length, ULONG Type, + ULONG Protect) +{ + PMM_REGION Region; + + Region = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION), + TAG_MM_REGION); + Region->Type = Type; + Region->Protect = Protect; + Region->Length = Length; + InitializeListHead(RegionListHead); + InsertHeadList(RegionListHead, &Region->RegionListEntry); +} + +PMM_REGION +MmFindRegion(PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, + PVOID* RegionBaseAddress) +{ + PLIST_ENTRY current_entry; + PMM_REGION current; + PVOID StartAddress = BaseAddress; + + current_entry = RegionListHead->Flink; + while (current_entry != RegionListHead) + { + current = CONTAINING_RECORD(current_entry, MM_REGION, RegionListEntry); + + if (StartAddress <= Address && + (StartAddress + current->Length) > Address) + { + if (RegionBaseAddress != NULL) + { + *RegionBaseAddress = StartAddress; + } + return(current); + } + + current_entry = current_entry->Flink; + StartAddress += current->Length; + } + return(NULL); +} diff --git a/reactos/ntoskrnl/mm/rmap.c b/reactos/ntoskrnl/mm/rmap.c index 049db4f4ddf..31a4a62c759 100644 --- a/reactos/ntoskrnl/mm/rmap.c +++ b/reactos/ntoskrnl/mm/rmap.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: rmap.c,v 1.6 2002/06/04 15:26:57 dwelch Exp $ +/* $Id: rmap.c,v 1.7 2002/08/10 16:41:19 dwelch Exp $ * * COPYRIGHT: See COPYING in the top directory * PROJECT: ReactOS kernel @@ -86,7 +86,7 @@ MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress) MmLockAddressSpace(&Process->AddressSpace); MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address); Type = MemoryArea->Type; - if (Type == MEMORY_AREA_SECTION_VIEW_COMMIT) + if (Type == MEMORY_AREA_SECTION_VIEW) { Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) + MemoryArea->Data.SectionData.ViewOffset); diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c index 323727aa939..4ded2d91908 100644 --- a/reactos/ntoskrnl/mm/section.c +++ b/reactos/ntoskrnl/mm/section.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: section.c,v 1.87 2002/08/08 17:54:15 dwelch Exp $ +/* $Id: section.c,v 1.88 2002/08/10 16:41:19 dwelch Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/mm/section.c @@ -36,6 +36,7 @@ #include #include #include +#include #define NDEBUG #include @@ -432,6 +433,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, ULONG Entry1; ULONG Attributes; PMM_PAGEOP PageOp; + PMM_REGION Region; /* * There is a window between taking the page fault and locking the @@ -456,6 +458,9 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, */ Segment = MemoryArea->Data.SectionData.Segment; Section = MemoryArea->Data.SectionData.Section; + Region = MmFindRegion(MemoryArea->BaseAddress, + &MemoryArea->Data.SectionData.RegionListHead, + Address, NULL); MmLockSection(Section); MmLockSectionSegment(Segment); @@ -591,7 +596,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, Status = MmCreateVirtualMapping(PsGetCurrentProcess(), Address, - MemoryArea->Attributes, + Region->Protect, Page, FALSE); while (Status == STATUS_NO_MEMORY) @@ -599,7 +604,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, MmUnlockAddressSpace(AddressSpace); Status = MmCreateVirtualMapping(PsGetCurrentProcess(), Address, - MemoryArea->Attributes, + Region->Protect, Page, TRUE); MmLockAddressSpace(AddressSpace); @@ -646,7 +651,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, */ Status = MmCreateVirtualMapping(PsGetCurrentProcess(), Address, - MemoryArea->Attributes, + Region->Protect, Offset, FALSE); /* @@ -689,7 +694,7 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, Status = MmCreateVirtualMapping(PsGetCurrentProcess(), Address, - MemoryArea->Attributes, + Region->Protect, Page, FALSE); MmInsertRmap(Page, PsGetCurrentProcess(), @@ -715,14 +720,14 @@ MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace, * Check if this page needs to be mapped COW */ if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) && - (MemoryArea->Attributes == PAGE_READWRITE || - MemoryArea->Attributes == PAGE_EXECUTE_READWRITE)) + (Region->Protect == PAGE_READWRITE || + Region->Protect == PAGE_EXECUTE_READWRITE)) { Attributes = PAGE_READONLY; } else { - Attributes = MemoryArea->Attributes; + Attributes = Region->Protect; } /* @@ -971,6 +976,7 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, ULONG PAddress; LARGE_INTEGER Offset; PMM_PAGEOP PageOp; + PMM_REGION Region; /* * Check if the page has been paged out or has already been set readwrite @@ -993,6 +999,9 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, */ Segment = MemoryArea->Data.SectionData.Segment; Section = MemoryArea->Data.SectionData.Section; + Region = MmFindRegion(MemoryArea->BaseAddress, + &MemoryArea->Data.SectionData.RegionListHead, + Address, NULL); MmLockSection(Section); MmLockSectionSegment(Segment); @@ -1009,8 +1018,8 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, * Check if we are doing COW */ if (!((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) && - (MemoryArea->Attributes == PAGE_READWRITE || - MemoryArea->Attributes == PAGE_EXECUTE_READWRITE))) + (Region->Protect == PAGE_READWRITE || + Region->Protect == PAGE_EXECUTE_READWRITE))) { MmUnlockSection(Section); MmUnlockSectionSegment(Segment); @@ -1094,7 +1103,7 @@ MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace, MmLockAddressSpace(AddressSpace); Status = MmCreateVirtualMapping(PsGetCurrentProcess(), Address, - MemoryArea->Attributes, + Region->Protect, NewPage, FALSE); MmInsertRmap(NewPage, PsGetCurrentProcess(), @@ -1494,6 +1503,125 @@ MmPageOutSectionView(PMADDRESS_SPACE AddressSpace, return(STATUS_SUCCESS); } +VOID STATIC +MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace, + PVOID BaseAddress, + ULONG RegionSize, + ULONG OldType, + ULONG OldProtect, + ULONG NewType, + ULONG NewProtect) +{ + PMEMORY_AREA MemoryArea; + PMM_SECTION_SEGMENT Segment; + BOOL DoCOW = FALSE; + ULONG i; + + MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress); + Segment = MemoryArea->Data.SectionData.Segment; + + if ((Segment->WriteCopy || MemoryArea->Data.SectionData.WriteCopyView) && + (NewProtect == PAGE_READWRITE || NewProtect == PAGE_EXECUTE_READWRITE)) + { + DoCOW = TRUE; + } + + if (OldProtect != NewProtect) + { + for (i = 0; i < (RegionSize / PAGESIZE); i++) + { + PVOID Address = BaseAddress + (i * PAGESIZE); + ULONG Protect = NewProtect; + + /* + * If we doing COW for this segment then check if the page is + * already private. + */ + if (DoCOW && MmIsPagePresent(AddressSpace->Process, Address)) + { + LARGE_INTEGER Offset; + ULONG Entry; + LARGE_INTEGER PhysicalAddress; + + Offset.QuadPart = + (ULONG)(Address - (ULONG)MemoryArea->BaseAddress) + + MemoryArea->Data.SectionData.ViewOffset; + Entry = MmGetPageEntrySectionSegment(Segment, Offset.QuadPart); + PhysicalAddress = + MmGetPhysicalAddressForProcess(AddressSpace->Process, Address); + + Protect = PAGE_READONLY; + if ((Segment->Characteristics & IMAGE_SECTION_CHAR_BSS || + IS_SWAP_FROM_SSE(Entry) || + (LONGLONG)PAGE_FROM_SSE(Entry) != PhysicalAddress.QuadPart)) + { + Protect = NewProtect; + } + } + + if (MmIsPagePresent(AddressSpace->Process, Address)) + { + MmSetPageProtect(AddressSpace->Process, BaseAddress, + Protect); + } + } + } +} + +NTSTATUS +MmProtectSectionView(PMADDRESS_SPACE AddressSpace, + PMEMORY_AREA MemoryArea, + PVOID BaseAddress, + ULONG Length, + ULONG Protect, + PULONG OldProtect) +{ + PMM_REGION Region; + NTSTATUS Status; + + Length = min(Length, MemoryArea->Length); + Region = MmFindRegion(MemoryArea->BaseAddress, + &MemoryArea->Data.SectionData.RegionListHead, + BaseAddress, NULL); + *OldProtect = Region->Protect; + Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress, + &MemoryArea->Data.SectionData.RegionListHead, + BaseAddress, Length, Region->Type, Protect, + MmAlterViewAttributes); + + return(Status); +} + +NTSTATUS STDCALL +MmQuerySectionView(PMEMORY_AREA MemoryArea, + PVOID Address, + PMEMORY_BASIC_INFORMATION Info, + PULONG ResultLength) +{ + PMM_REGION Region; + PVOID RegionBaseAddress; + + Region = MmFindRegion(MemoryArea->BaseAddress, + &MemoryArea->Data.SectionData.RegionListHead, + Address, &RegionBaseAddress); + Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address); + Info->AllocationBase = MemoryArea->BaseAddress; + Info->AllocationProtect = MemoryArea->Attributes; + Info->RegionSize = MemoryArea->Length; + Info->State = MEM_COMMIT; + Info->Protect = Region->Protect; + if (MemoryArea->Data.SectionData.Section->Flags & MM_IMAGE_SECTION) + { + Info->Type = MEM_IMAGE; + } + else + { + Info->Type = MEM_MAPPED; + } + + return(STATUS_SUCCESS); +} + VOID STDCALL MmpDeleteSection(PVOID ObjectBody) { @@ -2187,6 +2315,7 @@ MmCreateImageSection(PHANDLE SectionHandle, { ULONG i; ULONG Size; + ULONG Characteristics; Size = sizeof(MM_IMAGE_SECTION_OBJECT) + (sizeof(MM_SECTION_SEGMENT) * NrSegments); @@ -2226,27 +2355,27 @@ MmCreateImageSection(PHANDLE SectionHandle, /* * Set up the protection and write copy variables. */ - if ((ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_READABLE) || - (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_WRITABLE) || - (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_EXECUTABLE)) + Characteristics = ImageSections[i - 1].Characteristics; + if ((Characteristics & IMAGE_SECTION_CHAR_READABLE) || + (Characteristics & IMAGE_SECTION_CHAR_WRITABLE) || + (Characteristics & IMAGE_SECTION_CHAR_EXECUTABLE)) { SectionSegments[i].Protection = - SectionCharacteristicsToProtect[ImageSections[i-1].Characteristics >> 28]; + SectionCharacteristicsToProtect[Characteristics >> 28]; SectionSegments[i].WriteCopy = - !(ImageSections[i - 1].Characteristics & IMAGE_SECTION_CHAR_SHARED); + !(Characteristics & IMAGE_SECTION_CHAR_SHARED); } - else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_CODE) + else if (Characteristics & IMAGE_SECTION_CHAR_CODE) { SectionSegments[i].Protection = PAGE_EXECUTE_READ; SectionSegments[i].WriteCopy = TRUE; } - else if (ImageSections[i-1].Characteristics & - IMAGE_SECTION_CHAR_DATA) + else if (Characteristics & IMAGE_SECTION_CHAR_DATA) { SectionSegments[i].Protection = PAGE_READWRITE; SectionSegments[i].WriteCopy = TRUE; } - else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_BSS) + else if (Characteristics & IMAGE_SECTION_CHAR_BSS) { SectionSegments[i].Protection = PAGE_READWRITE; SectionSegments[i].WriteCopy = TRUE; @@ -2260,15 +2389,15 @@ MmCreateImageSection(PHANDLE SectionHandle, /* * Set up the attributes. */ - if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_CODE) + if (Characteristics & IMAGE_SECTION_CHAR_CODE) { SectionSegments[i].Attributes = 0; } - else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_DATA) + else if (Characteristics & IMAGE_SECTION_CHAR_DATA) { SectionSegments[i].Attributes = 0; } - else if (ImageSections[i-1].Characteristics & IMAGE_SECTION_CHAR_BSS) + else if (Characteristics & IMAGE_SECTION_CHAR_BSS) { SectionSegments[i].Attributes = MM_SECTION_SEGMENT_BSS; } @@ -2409,14 +2538,9 @@ MmMapViewOfSegment(PEPROCESS Process, NTSTATUS Status; KIRQL oldIrql; - if (Protect == PAGE_NOACCESS || Protect == PAGE_GUARD) - { - DPRINT1("Mapping inaccessible region between 0x%.8X and 0x%.8X\n", - (*BaseAddress), (*BaseAddress) + ViewSize); - } Status = MmCreateMemoryArea(Process, &Process->AddressSpace, - MEMORY_AREA_SECTION_VIEW_COMMIT, + MEMORY_AREA_SECTION_VIEW, BaseAddress, ViewSize, Protect, @@ -2442,6 +2566,8 @@ MmMapViewOfSegment(PEPROCESS Process, MArea->Data.SectionData.Section = Section; MArea->Data.SectionData.ViewOffset = ViewOffset; MArea->Data.SectionData.WriteCopyView = FALSE; + MmInitialiseRegion(&MArea->Data.SectionData.RegionListHead, + ViewSize, 0, Protect); return(STATUS_SUCCESS); } @@ -2612,7 +2738,9 @@ MmUnmapViewOfSection(PEPROCESS Process, PSECTION_OBJECT Section; PMM_SECTION_SEGMENT Segment; KIRQL oldIrql; - + PLIST_ENTRY CurrentEntry; + PMM_REGION CurrentRegion; + AddressSpace = &Process->AddressSpace; DPRINT("Opening memory area Process %x BaseAddress %x\n", @@ -2632,6 +2760,16 @@ MmUnmapViewOfSection(PEPROCESS Process, KeAcquireSpinLock(&Section->ViewListLock, &oldIrql); RemoveEntryList(&MemoryArea->Data.SectionData.ViewListEntry); KeReleaseSpinLock(&Section->ViewListLock, oldIrql); + + CurrentEntry = MemoryArea->Data.SectionData.RegionListHead.Flink; + while (CurrentEntry != &MemoryArea->Data.SectionData.RegionListHead) + { + CurrentRegion = + CONTAINING_RECORD(CurrentEntry, MM_REGION, RegionListEntry); + CurrentEntry = CurrentEntry->Flink; + ExFreePool(CurrentRegion); + } + if (MemoryArea->Data.SectionData.Section->Flags & SO_PHYSICAL_MEMORY) { Status = MmFreeMemoryArea(&Process->AddressSpace, @@ -3030,7 +3168,6 @@ MmMapViewOfSection(IN PVOID SectionObject, return(STATUS_SUCCESS); } - BOOLEAN STDCALL MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN PLARGE_INTEGER NewFileSize) diff --git a/reactos/ntoskrnl/mm/virtual.c b/reactos/ntoskrnl/mm/virtual.c index 6728a25c530..e4dc0e82695 100644 --- a/reactos/ntoskrnl/mm/virtual.c +++ b/reactos/ntoskrnl/mm/virtual.c @@ -1,14 +1,27 @@ -/* $Id: virtual.c,v 1.61 2002/06/11 22:09:02 dwelch Exp $ +/* + * ReactOS kernel + * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: virtual.c,v 1.62 2002/08/10 16:41:19 dwelch Exp $ * - * COPYRIGHT: See COPYING in the top directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/mm/virtual.c - * PURPOSE: implementing the Virtualxxx section of the win32 api + * PURPOSE: Implementing operations on virtual memory. * PROGRAMMER: David Welch - * UPDATE HISTORY: - * 09/4/98: Created - * 10/6/98: Corrections from Iwan Fatahi (i_fatahi@hotmail.com) - * 30/9/98: Implemented ZwxxxVirtualMemory functions */ /* INCLUDE *****************************************************************/ @@ -19,1033 +32,13 @@ #include #include #include +#include #define NDEBUG #include -/* TYPES *********************************************************************/ - -typedef struct _MM_SEGMENT -{ - ULONG Type; - ULONG Protect; - ULONG Length; - LIST_ENTRY SegmentListEntry; -} MM_SEGMENT, *PMM_SEGMENT; - -/* GLOBALS *******************************************************************/ - -#define TAG_MM_SEGMENT TAG('M', 'S', 'E', 'G') - /* FUNCTIONS *****************************************************************/ -PMM_SEGMENT -MmGetSegmentForAddress(PMEMORY_AREA MArea, - PVOID Address, - PVOID* PCurrentAddress) -/* - * FUNCTION: Get the segment corresponding to a particular memory area and - * address. - * ARGUMENTS: - * MArea (IN) = The memory area - * Address (IN) = The address to get the segment for - * PCurrentAddress (OUT) = The start of the segment - * RETURNS: - * The corresponding segment or NULL if an error occurred - */ -{ - PVOID CurrentAddress; - PMM_SEGMENT CurrentSegment; - PLIST_ENTRY Current; - - if (Address < MArea->BaseAddress || - Address >= (MArea->BaseAddress + MArea->Length)) - { - KeBugCheck(0); - *PCurrentAddress = NULL; - return(NULL); - } - - Current = MArea->Data.VirtualMemoryData.SegmentListHead.Flink; - CurrentAddress = MArea->BaseAddress; - while (Current != &MArea->Data.VirtualMemoryData.SegmentListHead) - { - CurrentSegment = CONTAINING_RECORD(Current, - MM_SEGMENT, - SegmentListEntry); - if (Address >= CurrentAddress && - Address < (CurrentAddress + CurrentSegment->Length)) - { - *PCurrentAddress = CurrentAddress; - return(CurrentSegment); - } - CurrentAddress = CurrentAddress + CurrentSegment->Length; - Current = Current->Flink; - } - KeBugCheck(0); - return(NULL); -} - -NTSTATUS -MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace, - PMEMORY_AREA MArea, - PVOID Address) -{ - return(STATUS_UNSUCCESSFUL); -} - - -NTSTATUS -MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace, - PMEMORY_AREA MemoryArea, - PVOID Address, - PMM_PAGEOP PageOp) -{ - PHYSICAL_ADDRESS PhysicalAddress; - BOOL WasDirty; - SWAPENTRY SwapEntry; - NTSTATUS Status; - PMDL Mdl; - - DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n", - Address, MemoryArea->Process->UniqueProcessId); - - /* - * Check for paging out from a deleted virtual memory area. - */ - if (MemoryArea->DeleteInProgress) - { - return(STATUS_UNSUCCESSFUL); - } - - /* - * Paging out code or readonly data is easy. - */ - if ((MemoryArea->Attributes & PAGE_READONLY) || - (MemoryArea->Attributes & PAGE_EXECUTE_READ)) - { - MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, - NULL, &PhysicalAddress); - MmDeleteAllRmaps(PhysicalAddress, NULL, NULL); - if (MmGetSavedSwapEntryPage(PhysicalAddress) != 0) - { - DPRINT1("Read-only page was swapped out.\n"); - KeBugCheck(0); - } - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); - - PageOp->Status = STATUS_SUCCESS; - KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); - MmReleasePageOp(PageOp); - return(STATUS_SUCCESS); - } - - /* - * Otherwise this is read-write data - */ - MmDisableVirtualMapping(MemoryArea->Process, Address, - &WasDirty, (PULONG)&PhysicalAddress); - if (PhysicalAddress.QuadPart == 0) - { - KeBugCheck(0); - } - if (!WasDirty) - { - MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL); - MmDeleteAllRmaps(PhysicalAddress, NULL, NULL); - if ((SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress)) != 0) - { - MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry); - MmSetSavedSwapEntryPage(PhysicalAddress, 0); - } - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); - PageOp->Status = STATUS_SUCCESS; - KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); - MmReleasePageOp(PageOp); - return(STATUS_SUCCESS); - } - - /* - * If necessary, allocate an entry in the paging file for this page - */ - SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress); - if (SwapEntry == 0) - { - SwapEntry = MmAllocSwapPage(); - if (SwapEntry == 0) - { - MmEnableVirtualMapping(MemoryArea->Process, Address); - PageOp->Status = STATUS_UNSUCCESSFUL; - KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); - MmReleasePageOp(PageOp); - return(STATUS_UNSUCCESSFUL); - } - } - - /* - * Write the page to the pagefile - */ - Mdl = MmCreateMdl(NULL, NULL, PAGESIZE); - MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress); - Status = MmWriteToSwapPage(SwapEntry, Mdl); - if (!NT_SUCCESS(Status)) - { - DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", - Status); - MmEnableVirtualMapping(MemoryArea->Process, Address); - PageOp->Status = STATUS_UNSUCCESSFUL; - KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); - MmReleasePageOp(PageOp); - return(STATUS_UNSUCCESSFUL); - } - - /* - * Otherwise we have succeeded, free the page - */ - DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", PhysicalAddress); - MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL); - MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry); - MmDeleteAllRmaps(PhysicalAddress, NULL, NULL); - MmSetSavedSwapEntryPage(PhysicalAddress, 0); - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress); - PageOp->Status = STATUS_SUCCESS; - KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); - MmReleasePageOp(PageOp); - return(STATUS_SUCCESS); -} - -NTSTATUS -MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace, - MEMORY_AREA* MemoryArea, - PVOID Address, - BOOLEAN Locked) -/* - * FUNCTION: Move data into memory to satisfy a page not present fault - * ARGUMENTS: - * AddressSpace = Address space within which the fault occurred - * MemoryArea = The memory area within which the fault occurred - * Address = The absolute address of fault - * RETURNS: Status - * NOTES: This function is called with the address space lock held. - */ -{ - PHYSICAL_ADDRESS Page; - NTSTATUS Status; - PMM_SEGMENT Segment; - PVOID CurrentAddress; - PMM_PAGEOP PageOp; - - /* - * There is a window between taking the page fault and locking the - * address space when another thread could load the page so we check - * that. - */ - if (MmIsPagePresent(NULL, Address)) - { - if (Locked) - { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); - } - return(STATUS_SUCCESS); - } - - /* - * Check for the virtual memory area being deleted. - */ - if (MemoryArea->DeleteInProgress) - { - return(STATUS_UNSUCCESSFUL); - } - - /* - * Get the segment corresponding to the virtual address - */ - Segment = MmGetSegmentForAddress(MemoryArea, Address, &CurrentAddress); - if (Segment == NULL) - { - return(STATUS_UNSUCCESSFUL); - } - if (Segment->Type == MEM_RESERVE) - { - return(STATUS_UNSUCCESSFUL); - } - - /* - * Get or create a page operation - */ - PageOp = MmGetPageOp(MemoryArea, (ULONG)PsGetCurrentProcessId(), - (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0, - MM_PAGEOP_PAGEIN); - if (PageOp == NULL) - { - DPRINT1("MmGetPageOp failed"); - KeBugCheck(0); - } - - /* - * Check if someone else is already handling this fault, if so wait - * for them - */ - if (PageOp->Thread != PsGetCurrentThread()) - { - MmUnlockAddressSpace(AddressSpace); - Status = KeWaitForSingleObject(&PageOp->CompletionEvent, - 0, - KernelMode, - FALSE, - NULL); - /* - * Check for various strange conditions - */ - if (Status != STATUS_SUCCESS) - { - DPRINT1("Failed to wait for page op\n"); - KeBugCheck(0); - } - if (PageOp->Status == STATUS_PENDING) - { - DPRINT1("Woke for page op before completion\n"); - KeBugCheck(0); - } - /* - * If this wasn't a pagein then we need to restart the handling - */ - if (PageOp->OpType != MM_PAGEOP_PAGEIN) - { - MmLockAddressSpace(AddressSpace); - MmReleasePageOp(PageOp); - return(STATUS_MM_RESTART_OPERATION); - } - /* - * If the thread handling this fault has failed then we don't retry - */ - if (!NT_SUCCESS(PageOp->Status)) - { - MmLockAddressSpace(AddressSpace); - MmReleasePageOp(PageOp); - return(Status); - } - MmLockAddressSpace(AddressSpace); - if (Locked) - { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); - } - MmReleasePageOp(PageOp); - return(STATUS_SUCCESS); - } - - /* - * Try to allocate a page - */ - Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page); - if (Status == STATUS_NO_MEMORY) - { - MmUnlockAddressSpace(AddressSpace); - Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page); - MmLockAddressSpace(AddressSpace); - } - - /* - * Handle swapped out pages. - */ - if (MmIsPageSwapEntry(NULL, Address)) - { - SWAPENTRY SwapEntry; - PMDL Mdl; - - MmDeletePageFileMapping(NULL, Address, &SwapEntry); - Mdl = MmCreateMdl(NULL, NULL, PAGESIZE); - MmBuildMdlFromPages(Mdl, (PULONG)&Page); - Status = MmReadFromSwapPage(SwapEntry, Mdl); - if (!NT_SUCCESS(Status)) - { - KeBugCheck(0); - } - MmSetSavedSwapEntryPage(Page, SwapEntry); - } - - /* - * Set the page. If we fail because we are out of memory then - * try again - */ - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), - Address, - MemoryArea->Attributes, - Page, - FALSE); - while (Status == STATUS_NO_MEMORY) - { - MmUnlockAddressSpace(AddressSpace); - Status = MmCreateVirtualMapping(PsGetCurrentProcess(), - Address, - MemoryArea->Attributes, - Page, - TRUE); - MmLockAddressSpace(AddressSpace); - } - if (!NT_SUCCESS(Status)) - { - DPRINT1("MmCreateVirtualMapping failed, not out of memory\n"); - KeBugCheck(0); - return(Status); - } - - /* - * Add the page to the process's working set - */ - MmInsertRmap(Page, PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address)); - - /* - * Finish the operation - */ - if (Locked) - { - MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address)); - } - PageOp->Status = STATUS_SUCCESS; - KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); - MmReleasePageOp(PageOp); - return(STATUS_SUCCESS); -} - -VOID STATIC -MmModifyAttributes(PMADDRESS_SPACE AddressSpace, - PVOID BaseAddress, - ULONG RegionSize, - ULONG OldType, - ULONG OldProtect, - ULONG NewType, - ULONG NewProtect) -/* - * FUNCTION: Modify the attributes of a memory region - */ -{ - /* - * If we are switching a previously committed region to reserved then - * free any allocated pages within the region - */ - if (NewType == MEM_RESERVE && OldType == MEM_COMMIT) - { - ULONG i; - - for (i=0; i <= (RegionSize/PAGESIZE); i++) - { - LARGE_INTEGER PhysicalAddr; - - if (MmIsPageSwapEntry(AddressSpace->Process, - BaseAddress + (i * PAGESIZE))) - { - SWAPENTRY SwapEntry; - - MmDeletePageFileMapping(AddressSpace->Process, - BaseAddress + (i * PAGESIZE), - &SwapEntry); - MmFreeSwapPage(SwapEntry); - } - else - { - PhysicalAddr = MmGetPhysicalAddress(BaseAddress + (i*PAGESIZE)); - MmDeleteVirtualMapping(AddressSpace->Process, - BaseAddress + (i*PAGESIZE), - FALSE, NULL, NULL); - if (PhysicalAddr.QuadPart != 0) - { - MmDeleteRmap(PhysicalAddr, AddressSpace->Process, - BaseAddress + (i * PAGESIZE)); - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr); - } - } - } - } - - /* - * If we are changing the protection attributes of a committed region then - * alter the attributes for any allocated pages within the region - */ - if (NewType == MEM_COMMIT && OldType == MEM_COMMIT && - OldProtect != NewProtect) - { - ULONG i; - - for (i=0; i <= (RegionSize/PAGESIZE); i++) - { - if (MmIsPagePresent(AddressSpace->Process, - BaseAddress + (i*PAGESIZE))) - { - MmSetPageProtect(AddressSpace->Process, - BaseAddress + (i*PAGESIZE), - NewProtect); - } - } - } -} - -VOID STATIC -InsertAfterEntry(PLIST_ENTRY Previous, - PLIST_ENTRY Entry) -/* - * FUNCTION: Insert a list entry after another entry in the list - */ -{ - Previous->Flink->Blink = Entry; - - Entry->Flink = Previous->Flink; - Entry->Blink = Previous; - - Previous->Flink = Entry; -} - -#if 0 -VOID STATIC -MmDumpSegmentsMemoryArea(PMEMORY_AREA MemoryArea) -{ - PVOID CurrentAddress; - PLIST_ENTRY CurrentEntry; - PMM_SEGMENT CurrentSegment; - PLIST_ENTRY ListHead; - - CurrentEntry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink; - ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead; - - CurrentAddress = MemoryArea->BaseAddress; - while (CurrentEntry != ListHead) - { - CurrentSegment = CONTAINING_RECORD(CurrentEntry, - MM_SEGMENT, - SegmentListEntry); - - DbgPrint("0x%x 0x%x %d %d\n", - CurrentAddress, - CurrentSegment->Length, - CurrentSegment->Type, - CurrentSegment->Protect); - - CurrentAddress = CurrentAddress + CurrentSegment->Length; - CurrentEntry = CurrentEntry->Flink; - } -} -#endif - -NTSTATUS -MmSplitSegment(PMADDRESS_SPACE AddressSpace, - PMEMORY_AREA MemoryArea, - PVOID RegionAddress, - ULONG RegionLength, - ULONG Type, - ULONG Protect, - PMM_SEGMENT FirstSegment, - PVOID FirstAddress) -/* - * FUNCTION: Split a memory segment internally - */ -{ - PMM_SEGMENT NewTopSegment; - PMM_SEGMENT RegionSegment; - ULONG OldType; - ULONG OldProtect; - ULONG OldLength; - - DPRINT("MmSplitSegment()\n"); - /* - * Save the type and protection and length of the current segment - */ - OldType = FirstSegment->Type; - OldProtect = FirstSegment->Protect; - OldLength = FirstSegment->Length; - - /* - * If the segment is already of the right type and protection then - * there is nothing to do. - */ - if (FirstSegment->Type == Type && FirstSegment->Protect == Protect) - { - return(STATUS_SUCCESS); - } - - /* - * Allocate the segment we might need here because if the allocation - * fails below it will be difficult to undo what we've done already. - */ - NewTopSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT), - TAG_MM_SEGMENT); - if (NewTopSegment == NULL) - { - return(STATUS_NO_MEMORY); - } - - if (FirstAddress < RegionAddress) - { - /* - * If the region to be affected starts at a higher address than - * the current segment then create a new segment for the - * affected portion - */ - RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT), - TAG_MM_SEGMENT); - if (RegionSegment == NULL) - { - ExFreePool(NewTopSegment); - return(STATUS_NO_MEMORY); - } - - RegionSegment->Type = Type; - RegionSegment->Protect = Protect; - RegionSegment->Length = RegionLength; - - FirstSegment->Length = RegionAddress - FirstAddress; - - InsertAfterEntry(&FirstSegment->SegmentListEntry, - &RegionSegment->SegmentListEntry); - } - else - { - /* - * Otherwise just set its type and protection and length - */ - - FirstSegment->Type = Type; - FirstSegment->Protect = Protect; - FirstSegment->Length = RegionLength; - - RegionSegment = FirstSegment; - } - - if ((FirstAddress + OldLength) > (RegionAddress + RegionLength)) - { - /* - * If the top of the current segment extends after the affected - * region then create a segment for the unaffected portion - */ - - NewTopSegment->Type = OldType; - NewTopSegment->Protect = OldProtect; - NewTopSegment->Length = (FirstAddress + OldLength) - - (RegionAddress + RegionLength); - - InsertAfterEntry(&RegionSegment->SegmentListEntry, - &NewTopSegment->SegmentListEntry); - } - else - { - ExFreePool(NewTopSegment); - NewTopSegment = NULL; - } - - /* - * Actually set the type and protection of the affected region - */ - MmModifyAttributes(AddressSpace, - RegionAddress, - RegionLength, - OldType, - OldProtect, - Type, - Protect); - return(STATUS_SUCCESS); -} - -NTSTATUS MmGatherSegment(PMADDRESS_SPACE AddressSpace, - PMEMORY_AREA MemoryArea, - PVOID RegionAddress, - ULONG RegionLength, - ULONG Type, - ULONG Protect, - PMM_SEGMENT FirstSegment, - PVOID FirstAddress) -/* - * FUNCTION: Do a virtual memory operation that will effect several - * memory segments. - * ARGUMENTS: - * AddressSpace (IN) = Address space to affect - * MemoryArea (IN) = Memory area to affect - * BaseAddress (IN) = Base address of the region to affect - * RegionSize (IN) = Size of the region to affect - * Type (IN) = New type of the region - * Protect (IN) = New protection of the region - * CurrentSegment (IN) = First segment intersecting with the region - * CurrentAddress (IN) = Start address of the first segment - * interesting with the region - * RETURNS: Status - */ -{ - PMM_SEGMENT RegionSegment; - PVOID CurrentAddress; - ULONG RemainingLength; - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY ListHead; - PMM_SEGMENT CurrentSegment; - - if (FirstAddress < RegionAddress) - { - /* - * If a portion of the first segment is not covered by the region then - * we need to split it into two segments - */ - - RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT), - TAG_MM_SEGMENT); - if (RegionSegment == NULL) - { - return(STATUS_NO_MEMORY); - } - - RegionSegment->Type = Type; - RegionSegment->Protect = Protect; - RegionSegment->Length = (FirstAddress + FirstSegment->Length) - - RegionAddress; - - FirstSegment->Length = RegionAddress - FirstAddress; - - InsertAfterEntry(&FirstSegment->SegmentListEntry, - &RegionSegment->SegmentListEntry); - - MmModifyAttributes(AddressSpace, - RegionAddress, - RegionSegment->Length, - FirstSegment->Type, - FirstSegment->Protect, - Type, - Protect); - - CurrentAddress = FirstAddress + FirstSegment->Length + - RegionSegment->Length; - } - else - { - /* - * Otherwise just change the attributes of the segment - */ - - ULONG OldType; - ULONG OldProtect; - - OldType = FirstSegment->Type; - OldProtect = FirstSegment->Protect; - - FirstSegment->Type = Type; - FirstSegment->Protect = Protect; - - RegionSegment = FirstSegment; - - MmModifyAttributes(AddressSpace, - RegionAddress, - FirstSegment->Length, - OldType, - OldProtect, - Type, - Protect); - - CurrentAddress = FirstAddress + RegionSegment->Length; - } - - /* - * Change the attributes of all the complete segments lying inside the - * affected region - */ - RemainingLength = RegionLength - RegionSegment->Length; - CurrentEntry = RegionSegment->SegmentListEntry.Flink; - CurrentSegment = CONTAINING_RECORD(CurrentEntry, - MM_SEGMENT, - SegmentListEntry); - ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead; - - while (CurrentEntry != ListHead && RemainingLength > 0) - { - ULONG OldType; - ULONG OldProtect; - ULONG OldLength; - - /* - * If this segment will not be completely covered by the - * affected region then break - */ - if (CurrentSegment->Length > RemainingLength) - { - break; - } - - OldType = CurrentSegment->Type; - OldProtect = CurrentSegment->Protect; - OldLength = CurrentSegment->Length; - - /* - * Extend the length of the previous segment to cover this one - */ - RegionSegment->Length = RegionSegment->Length + OldLength; - RemainingLength = RemainingLength - OldLength; - CurrentAddress = CurrentAddress + OldLength; - CurrentEntry = CurrentEntry->Flink; - - /* - * Remove the current segment from the list - */ - RemoveEntryList(&CurrentSegment->SegmentListEntry); - ExFreePool(CurrentSegment); - - MmModifyAttributes(AddressSpace, - CurrentAddress, - OldLength, - OldType, - OldProtect, - Type, - Protect); - - CurrentSegment = CONTAINING_RECORD(CurrentEntry, - MM_SEGMENT, - SegmentListEntry); - } - - /* - * If we've run off the top of the memory area then bug check - */ - if (CurrentEntry == ListHead && RemainingLength > 0) - { - KeBugCheck(0); - } - - /* - * We've only affected a portion of a segment then split it in two - */ - if (RemainingLength > 0) - { - CurrentSegment->Length = CurrentSegment->Length - RemainingLength; - - RegionSegment->Length = RegionSegment->Length + RemainingLength; - - MmModifyAttributes(AddressSpace, - CurrentAddress, - RemainingLength, - CurrentSegment->Type, - CurrentSegment->Protect, - Type, - Protect); - } - - return(STATUS_SUCCESS); -} - -NTSTATUS MmComplexVirtualMemoryOperation(PMADDRESS_SPACE AddressSpace, - PMEMORY_AREA MemoryArea, - PVOID BaseAddress, - ULONG RegionSize, - ULONG Type, - ULONG Protect) -{ - PMM_SEGMENT CurrentSegment; - PVOID CurrentAddress; - - CurrentSegment = MmGetSegmentForAddress(MemoryArea, - BaseAddress, - &CurrentAddress); - if (CurrentSegment == NULL) - { - KeBugCheck(0); - } - - if (BaseAddress >= CurrentAddress && - (BaseAddress + RegionSize) <= (CurrentAddress + CurrentSegment->Length)) - { - return((MmSplitSegment(AddressSpace, - MemoryArea, - BaseAddress, - RegionSize, - Type, - Protect, - CurrentSegment, - CurrentAddress))); - } - else - { - return((MmGatherSegment(AddressSpace, - MemoryArea, - BaseAddress, - RegionSize, - Type, - Protect, - CurrentSegment, - CurrentAddress))); - } -} - - -NTSTATUS STDCALL -NtAllocateVirtualMemory(IN HANDLE ProcessHandle, - IN OUT PVOID* UBaseAddress, - IN ULONG ZeroBits, - IN OUT PULONG URegionSize, - IN ULONG AllocationType, - IN ULONG Protect) -/* - * FUNCTION: Allocates a block of virtual memory in the process address space - * ARGUMENTS: - * ProcessHandle = The handle of the process which owns the virtual memory - * BaseAddress = A pointer to the virtual memory allocated. If you - * supply a non zero value the system will try to - * allocate the memory at the address supplied. It round - * it down to a multiple of the page size. - * ZeroBits = (OPTIONAL) You can specify the number of high order bits - * that must be zero, ensuring that the memory will be - * allocated at a address below a certain value. - * RegionSize = The number of bytes to allocate - * AllocationType = Indicates the type of virtual memory you like to - * allocated, can be a combination of MEM_COMMIT, - * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN. - * Protect = Indicates the protection type of the pages allocated, can be - * a combination of PAGE_READONLY, PAGE_READWRITE, - * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD, - * PAGE_NOACCESS - * REMARKS: - * This function maps to the win32 VirtualAllocEx. Virtual memory is - * process based so the protocol starts with a ProcessHandle. I - * splitted the functionality of obtaining the actual address and - * specifying the start address in two parameters ( BaseAddress and - * StartAddress ) The NumberOfBytesAllocated specify the range and the - * AllocationType and ProctectionType map to the other two parameters. - * RETURNS: Status - */ -{ - PEPROCESS Process; - MEMORY_AREA* MemoryArea; - ULONG Type; - NTSTATUS Status; - PMADDRESS_SPACE AddressSpace; - PMM_SEGMENT Segment; - PVOID BaseAddress; - ULONG RegionSize; - PVOID PBaseAddress; - ULONG PRegionSize; - - DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, " - "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n", - *UBaseAddress,ZeroBits,*URegionSize,AllocationType, - Protect); - - /* - * Check the validity of the parameters - */ - if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect) - { - return(STATUS_INVALID_PAGE_PROTECTION); - } - if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0) - { - return(STATUS_INVALID_PARAMETER); - } - if (((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == MEM_COMMIT) && - (*UBaseAddress == 0)) - { - /* Fix for badly behaved vc applications. */ - AllocationType |= MEM_RESERVE; - } - - PBaseAddress = *UBaseAddress; - PRegionSize = *URegionSize; - - - BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress); - RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) - - PAGE_ROUND_DOWN(PBaseAddress); - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_OPERATION, - NULL, - UserMode, - (PVOID*)(&Process), - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtAllocateVirtualMemory() = %x\n",Status); - return(Status); - } - - Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE; - DPRINT("Type %x\n", Type); - - AddressSpace = &Process->AddressSpace; - MmLockAddressSpace(AddressSpace); - - if ((PBaseAddress != 0) && - ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == MEM_COMMIT)) - { - MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, - BaseAddress); - - if (MemoryArea != NULL && - MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY && - MemoryArea->Length >= RegionSize) - { - Status = MmComplexVirtualMemoryOperation(AddressSpace, - MemoryArea, - BaseAddress, - RegionSize, - Type, - Protect); - /* FIXME: Reserve/dereserve swap pages */ - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - DPRINT("NtAllocateVirtualMemory() = %x\n",Status); - return(Status); - } - else if (MemoryArea != NULL) - { - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_UNSUCCESSFUL); - } - } - - Segment = ExAllocatePoolWithTag(NonPagedPool, - sizeof(MM_SEGMENT), - TAG_MM_SEGMENT); - if (Segment == NULL) - { - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_UNSUCCESSFUL); - } - - Status = MmCreateMemoryArea(Process, - &Process->AddressSpace, - MEMORY_AREA_VIRTUAL_MEMORY, - &BaseAddress, - RegionSize, - Protect, - &MemoryArea, - PBaseAddress != 0); - - if (!NT_SUCCESS(Status)) - { - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - DPRINT("NtAllocateVirtualMemory() = %x\n",Status); - return(Status); - } - - InitializeListHead(&MemoryArea->Data.VirtualMemoryData.SegmentListHead); - - Segment->Type = Type; - Segment->Protect = Protect; - Segment->Length = RegionSize; - InsertTailList(&MemoryArea->Data.VirtualMemoryData.SegmentListHead, - &Segment->SegmentListEntry); - - if ((AllocationType & MEM_COMMIT) && - ((Protect & PAGE_READWRITE) || - (Protect & PAGE_EXECUTE_READWRITE))) - { - MmReserveSwapPages(RegionSize); - } - - *UBaseAddress = BaseAddress; - *URegionSize = RegionSize; - DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize); - - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_SUCCESS); -} - - NTSTATUS STDCALL NtFlushVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, @@ -1062,188 +55,9 @@ NtFlushVirtualMemory(IN HANDLE ProcessHandle, * RETURNS: Status */ { - UNIMPLEMENTED; + UNIMPLEMENTED; } -VOID STATIC -MmFreeVirtualMemoryPage(PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PHYSICAL_ADDRESS PhysicalAddr, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - PEPROCESS Process = (PEPROCESS)Context; - - if (PhysicalAddr.QuadPart != 0) - { - MmDeleteRmap(PhysicalAddr, Process, Address); - MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr); - } - else if (SwapEntry != 0) - { - MmFreeSwapPage(SwapEntry); - } -} - -VOID -MmFreeVirtualMemory(PEPROCESS Process, - PMEMORY_AREA MemoryArea) -{ - PLIST_ENTRY current_entry; - PMM_SEGMENT current; - ULONG i; - - DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process, - MemoryArea); - - /* Mark this memory area as about to be deleted. */ - MemoryArea->DeleteInProgress = TRUE; - - /* - * Wait for any ongoing paging operations. Notice that since we have - * flagged this memory area as deleted no more page ops will be added. - */ - if (MemoryArea->PageOpCount > 0) - { - for (i = 0; i < (PAGE_ROUND_UP(MemoryArea->Length) / PAGESIZE); i++) - { - PMM_PAGEOP PageOp; - - if (MemoryArea->PageOpCount == 0) - { - break; - } - - PageOp = MmCheckForPageOp(MemoryArea, Process->UniqueProcessId, - MemoryArea->BaseAddress + (i * PAGESIZE), - NULL, 0); - if (PageOp != NULL) - { - NTSTATUS Status; - MmUnlockAddressSpace(&Process->AddressSpace); - Status = KeWaitForSingleObject(&PageOp->CompletionEvent, - 0, - KernelMode, - FALSE, - NULL); - if (Status != STATUS_SUCCESS) - { - DPRINT1("Failed to wait for page op\n"); - KeBugCheck(0); - } - MmLockAddressSpace(&Process->AddressSpace); - MmReleasePageOp(PageOp); - } - } - } - - /* Free all the individual segments. */ - current_entry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink; - while (current_entry != &MemoryArea->Data.VirtualMemoryData.SegmentListHead) - { - current = CONTAINING_RECORD(current_entry, MM_SEGMENT, SegmentListEntry); - current_entry = current_entry->Flink; - DPRINT("ExFreePool(%p)\n", current); - ExFreePool(current); - } - - /* Actually free the memory area. */ - MmFreeMemoryArea(&Process->AddressSpace, - MemoryArea->BaseAddress, - 0, - MmFreeVirtualMemoryPage, - (PVOID)Process); -} - -NTSTATUS STDCALL -NtFreeVirtualMemory(IN HANDLE ProcessHandle, - IN PVOID* PBaseAddress, - IN PULONG PRegionSize, - IN ULONG FreeType) -/* - * FUNCTION: Frees a range of virtual memory - * ARGUMENTS: - * ProcessHandle = Points to the process that allocated the virtual - * memory - * BaseAddress = Points to the memory address, rounded down to a - * multiple of the pagesize - * RegionSize = Limits the range to free, rounded up to a multiple of - * the paging size - * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE - * RETURNS: Status - */ -{ - MEMORY_AREA* MemoryArea; - NTSTATUS Status; - PEPROCESS Process; - PMADDRESS_SPACE AddressSpace; - PVOID BaseAddress; - ULONG RegionSize; - - DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, " - "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress, - *PRegionSize,FreeType); - - BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress)); - RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) - - PAGE_ROUND_DOWN((*PBaseAddress)); - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_OPERATION, - PsProcessType, - UserMode, - (PVOID*)(&Process), - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - AddressSpace = &Process->AddressSpace; - - MmLockAddressSpace(AddressSpace); - MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, - BaseAddress); - if (MemoryArea == NULL) - { - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_UNSUCCESSFUL); - } - - switch (FreeType) - { - case MEM_RELEASE: - /* We can only free a memory area in one step. */ - if (MemoryArea->BaseAddress != BaseAddress) - { - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_UNSUCCESSFUL); - } - MmFreeVirtualMemory(Process, MemoryArea); - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_SUCCESS); - - case MEM_DECOMMIT: - Status = MmComplexVirtualMemoryOperation(AddressSpace, - MemoryArea, - BaseAddress, - RegionSize, - MEM_RESERVE, - PAGE_NOACCESS); - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(Status); - } - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_NOT_IMPLEMENTED); -} - - NTSTATUS STDCALL NtLockVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, @@ -1253,38 +67,115 @@ NtLockVirtualMemory(HANDLE ProcessHandle, UNIMPLEMENTED; } - -VOID -MmChangeAreaProtection(PEPROCESS Process, - PVOID BaseAddress, - ULONG Length, - ULONG Protect) +NTSTATUS STDCALL +NtQueryVirtualMemory (IN HANDLE ProcessHandle, + IN PVOID Address, + IN CINT VirtualMemoryInformationClass, + OUT PVOID VirtualMemoryInformation, + IN ULONG Length, + OUT PULONG UnsafeResultLength) { - ULONG i; + NTSTATUS Status; + PEPROCESS Process; + MEMORY_AREA* MemoryArea; + ULONG ResultLength = 0; + PMADDRESS_SPACE AddressSpace; - for (i=0; i<(Length/PAGESIZE); i++) + DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, " + "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, " + "Length %lu ResultLength %x)\n",ProcessHandle,Address, + VirtualMemoryInformationClass,VirtualMemoryInformation, + Length,ResultLength); + + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_QUERY_INFORMATION, + NULL, + UserMode, + (PVOID*)(&Process), + NULL); + + if (!NT_SUCCESS(Status)) { - if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE))) - { - MmSetPageProtect(Process, - BaseAddress + (i*PAGESIZE), - Protect); - } + DPRINT("NtQueryVirtualMemory() = %x\n",Status); + return(Status); + } + + AddressSpace = &Process->AddressSpace; + MmLockAddressSpace(AddressSpace); + MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, + Address); + switch(VirtualMemoryInformationClass) + { + case MemoryBasicInformation: + { + PMEMORY_BASIC_INFORMATION Info = + (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation; + + if (Length != sizeof(MEMORY_BASIC_INFORMATION)) + { + ObDereferenceObject(Process); + return(STATUS_INFO_LENGTH_MISMATCH); + } + + if (MemoryArea == NULL) + { + Info->State = MEM_FREE; + Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address); + Status = STATUS_SUCCESS; + ResultLength = sizeof(MEMORY_BASIC_INFORMATION); + } + else if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY) + { + Status = MmQueryAnonMem(MemoryArea, Address, Info, + &ResultLength); + } + else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) + { + Status = MmQuerySectionView(MemoryArea, Address, Info, + &ResultLength); + } + else + { + Status = STATUS_UNSUCCESSFUL; + ResultLength = 0; + } + break; + } + + default: + { + Status = STATUS_INVALID_INFO_CLASS; + ResultLength = 0; + break; + } } -} + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + if (UnsafeResultLength != NULL) + { + MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG)); + } + return(Status); +} NTSTATUS STDCALL NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN ULONG NumberOfBytesToProtect, IN ULONG NewAccessProtection, - OUT PULONG OldAccessProtection) + OUT PULONG UnsafeOldAccessProtection) { PMEMORY_AREA MemoryArea; PEPROCESS Process; NTSTATUS Status; PMADDRESS_SPACE AddressSpace; + ULONG OldAccessProtection; + + NumberOfBytesToProtect = + PAGE_ROUND_UP(BaseAddress + NumberOfBytesToProtect) - + PAGE_ROUND_DOWN(BaseAddress); + BaseAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress); Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_VM_OPERATION, @@ -1305,132 +196,34 @@ NtProtectVirtualMemory(IN HANDLE ProcessHandle, BaseAddress); if (MemoryArea == NULL) { - DPRINT("NtProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL); - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return(STATUS_UNSUCCESSFUL); + MmUnlockAddressSpace(AddressSpace); + ObDereferenceObject(Process); + return(STATUS_UNSUCCESSFUL); } -#if 0 - *OldAccessProtection = MemoryArea->Attributes; - - if (MemoryArea->BaseAddress == BaseAddress && - MemoryArea->Length == NumberOfBytesToProtect) + + if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY) { - MemoryArea->Attributes = NewAccessProtection; + Status = MmProtectAnonMem(AddressSpace, MemoryArea, BaseAddress, + NumberOfBytesToProtect, NewAccessProtection, + &OldAccessProtection); } - else + else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) { - MemoryArea = MmSplitMemoryArea(Process, - &Process->AddressSpace, - MemoryArea, - BaseAddress, - NumberOfBytesToProtect, - MemoryArea->Type, - NewAccessProtection); + Status = MmProtectSectionView(AddressSpace, MemoryArea, BaseAddress, + NumberOfBytesToProtect, + NewAccessProtection, + &OldAccessProtection); } - MmChangeAreaProtection(Process, - BaseAddress, - NumberOfBytesToProtect, - NewAccessProtection); -#endif + MmUnlockAddressSpace(AddressSpace); ObDereferenceObject(Process); - return(STATUS_SUCCESS); + + MmCopyToCaller(UnsafeOldAccessProtection, &OldAccessProtection, + sizeof(ULONG)); + + return(Status); } - -NTSTATUS STDCALL -NtQueryVirtualMemory (IN HANDLE ProcessHandle, - IN PVOID Address, - IN CINT VirtualMemoryInformationClass, - OUT PVOID VirtualMemoryInformation, - IN ULONG Length, - OUT PULONG ResultLength) -{ - NTSTATUS Status; - PEPROCESS Process; - MEMORY_AREA* MemoryArea; - - DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, " - "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, " - "Length %lu ResultLength %x)\n",ProcessHandle,Address, - VirtualMemoryInformationClass,VirtualMemoryInformation, - Length,ResultLength); - - switch(VirtualMemoryInformationClass) - { - case MemoryBasicInformation: - { - PMEMORY_BASIC_INFORMATION Info = - (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation; - PMADDRESS_SPACE AddressSpace; - - if (Length < sizeof(MEMORY_BASIC_INFORMATION)) - { - ObDereferenceObject(Process); - return STATUS_INFO_LENGTH_MISMATCH; - } - - if (ResultLength) - { - *ResultLength = sizeof(MEMORY_BASIC_INFORMATION); - } - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_QUERY_INFORMATION, - NULL, - UserMode, - (PVOID*)(&Process), - NULL); - - if (!NT_SUCCESS(Status)) - { - DPRINT("NtQueryVirtualMemory() = %x\n",Status); - return(Status); - } - - AddressSpace = &Process->AddressSpace; - MmLockAddressSpace(AddressSpace); - MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, - Address); - - if (MemoryArea == NULL) - { - Info->State = MEM_FREE; - DPRINT("Virtual memory at %p is free.\n", Address); - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return (STATUS_SUCCESS); - } - -#if 0 - if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY) - { - Info->State = MEM_COMMIT; - } - else - { - Info->State = MEM_RESERVE; - } -#endif - - Info->BaseAddress = MemoryArea->BaseAddress; - Info->RegionSize = MemoryArea->Length; - - DPRINT("BaseAddress %p, RegionSize %x State %x\n", - Info->BaseAddress, Info->RegionSize, Info->State); - - MmUnlockAddressSpace(AddressSpace); - ObDereferenceObject(Process); - return STATUS_SUCCESS; - } - break; - } - - return STATUS_INVALID_INFO_CLASS; -} - - NTSTATUS STDCALL NtReadVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, @@ -1438,61 +231,60 @@ NtReadVirtualMemory(IN HANDLE ProcessHandle, IN ULONG NumberOfBytesToRead, OUT PULONG NumberOfBytesRead) { - NTSTATUS Status; - PMDL Mdl; - PVOID SystemAddress; - PEPROCESS Process; - - DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, " - "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress, - Buffer,NumberOfBytesToRead); - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_VM_WRITE, - NULL, - UserMode, - (PVOID*)(&Process), - NULL); - if (Status != STATUS_SUCCESS) - { - return(Status); - } - - Mdl = MmCreateMdl(NULL, - Buffer, - NumberOfBytesToRead); - MmProbeAndLockPages(Mdl, - UserMode, - IoWriteAccess); - - KeAttachProcess(Process); - - SystemAddress = MmGetSystemAddressForMdl(Mdl); - memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead); - - KeDetachProcess(); - - if (Mdl->MappedSystemVa != NULL) - { - MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); - } - MmUnlockPages(Mdl); - ExFreePool(Mdl); - - ObDereferenceObject(Process); - - *NumberOfBytesRead = NumberOfBytesToRead; - return(STATUS_SUCCESS); + NTSTATUS Status; + PMDL Mdl; + PVOID SystemAddress; + PEPROCESS Process; + + DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, " + "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress, + Buffer,NumberOfBytesToRead); + + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_VM_WRITE, + NULL, + UserMode, + (PVOID*)(&Process), + NULL); + if (Status != STATUS_SUCCESS) + { + return(Status); + } + + Mdl = MmCreateMdl(NULL, + Buffer, + NumberOfBytesToRead); + MmProbeAndLockPages(Mdl, + UserMode, + IoWriteAccess); + + KeAttachProcess(Process); + + SystemAddress = MmGetSystemAddressForMdl(Mdl); + memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead); + + KeDetachProcess(); + + if (Mdl->MappedSystemVa != NULL) + { + MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); + } + MmUnlockPages(Mdl); + ExFreePool(Mdl); + + ObDereferenceObject(Process); + + *NumberOfBytesRead = NumberOfBytesToRead; + return(STATUS_SUCCESS); } - NTSTATUS STDCALL NtUnlockVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, ULONG NumberOfBytesToUnlock, PULONG NumberOfBytesUnlocked OPTIONAL) { - UNIMPLEMENTED; + UNIMPLEMENTED; } @@ -1532,13 +324,9 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle, KeAttachProcess(Process); - DPRINT("Attached to process copying memory\n"); - SystemAddress = MmGetSystemAddressForMdl(Mdl); memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite); - DPRINT("Done copy\n"); - KeDetachProcess(); ObDereferenceObject(Process); @@ -1552,12 +340,9 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle, *NumberOfBytesWritten = NumberOfBytesToWrite; - DPRINT("Finished NtWriteVirtualMemory()\n"); - return(STATUS_SUCCESS); } - DWORD STDCALL MmSecureVirtualMemory (DWORD Unknown0, DWORD Unknown1, diff --git a/reactos/ntoskrnl/rtl/seh.c b/reactos/ntoskrnl/rtl/seh.c index 9d5bb81b847..778119ed788 100644 --- a/reactos/ntoskrnl/rtl/seh.c +++ b/reactos/ntoskrnl/rtl/seh.c @@ -62,6 +62,19 @@ extern DWORD CDECL SEHFilterRoutine(VOID); extern VOID CDECL SEHHandlerRoutine(VOID); #endif +DWORD CDECL SEHFilterRoutine(VOID) +{ + DbgPrint("Within filter routine.\n"); + return EXCEPTION_EXECUTE_HANDLER; + //return EXCEPTION_CONTINUE_EXECUTION; +} + +VOID CDECL SEHHandlerRoutine(VOID) +{ + DbgPrint("Within exception handler.\n"); + DbgPrint("System halted.\n"); + for (;;); +} EXCEPTION_DISPOSITION CDECL diff --git a/reactos/test.commit b/reactos/test.commit deleted file mode 100644 index 80dbb155a74..00000000000 --- a/reactos/test.commit +++ /dev/null @@ -1,3 +0,0 @@ - -this file added to test commit mailer -