2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/virtual.c
5 * PURPOSE: Implementing operations on virtual memory.
7 * PROGRAMMERS: David Welch
10 /* INCLUDE ********************************************************************/
16 /* PRIVATE FUNCTIONS **********************************************************/
19 MiQueryVirtualMemory(IN HANDLE ProcessHandle
,
21 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
22 OUT PVOID VirtualMemoryInformation
,
24 OUT PSIZE_T ResultLength
)
28 MEMORY_AREA
* MemoryArea
;
29 PMMSUPPORT AddressSpace
;
31 Status
= ObReferenceObjectByHandle(ProcessHandle
,
32 PROCESS_QUERY_INFORMATION
,
38 if (!NT_SUCCESS(Status
))
40 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
44 AddressSpace
= &Process
->Vm
;
46 MmLockAddressSpace(AddressSpace
);
47 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
48 switch(VirtualMemoryInformationClass
)
50 case MemoryBasicInformation
:
52 PMEMORY_BASIC_INFORMATION Info
=
53 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
54 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
56 MmUnlockAddressSpace(AddressSpace
);
57 ObDereferenceObject(Process
);
58 return(STATUS_INFO_LENGTH_MISMATCH
);
61 if (MemoryArea
== NULL
)
64 Info
->State
= MEM_FREE
;
65 Info
->Protect
= PAGE_NOACCESS
;
66 Info
->AllocationProtect
= 0;
67 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
68 Info
->AllocationBase
= NULL
;
69 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
70 Status
= STATUS_SUCCESS
;
71 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
75 switch(MemoryArea
->Type
)
77 case MEMORY_AREA_VIRTUAL_MEMORY
:
78 case MEMORY_AREA_PEB_OR_TEB
:
79 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
83 case MEMORY_AREA_SECTION_VIEW
:
84 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
88 case MEMORY_AREA_NO_ACCESS
:
89 Info
->Type
= MEM_PRIVATE
;
90 Info
->State
= MEM_RESERVE
;
91 Info
->Protect
= MemoryArea
->Protect
;
92 Info
->AllocationProtect
= MemoryArea
->Protect
;
93 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
94 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
95 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
96 (ULONG_PTR
)MemoryArea
->StartingAddress
;
97 Status
= STATUS_SUCCESS
;
98 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
101 case MEMORY_AREA_SHARED_DATA
:
102 Info
->Type
= MEM_PRIVATE
;
103 Info
->State
= MEM_COMMIT
;
104 Info
->Protect
= MemoryArea
->Protect
;
105 Info
->AllocationProtect
= MemoryArea
->Protect
;
106 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
107 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
108 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
109 (ULONG_PTR
)MemoryArea
->StartingAddress
;
110 Status
= STATUS_SUCCESS
;
111 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
114 case MEMORY_AREA_SYSTEM
:
116 Info
->State
= MEM_COMMIT
;
117 Info
->Protect
= MemoryArea
->Protect
;
118 Info
->AllocationProtect
= MemoryArea
->Protect
;
119 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
120 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
121 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
122 (ULONG_PTR
)MemoryArea
->StartingAddress
;
123 Status
= STATUS_SUCCESS
;
124 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
127 case MEMORY_AREA_KERNEL_STACK
:
129 Info
->State
= MEM_COMMIT
;
130 Info
->Protect
= MemoryArea
->Protect
;
131 Info
->AllocationProtect
= MemoryArea
->Protect
;
132 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
133 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
134 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
135 (ULONG_PTR
)MemoryArea
->StartingAddress
;
136 Status
= STATUS_SUCCESS
;
137 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
140 case MEMORY_AREA_PAGED_POOL
:
142 Info
->State
= MEM_COMMIT
;
143 Info
->Protect
= MemoryArea
->Protect
;
144 Info
->AllocationProtect
= MemoryArea
->Protect
;
145 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
146 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
147 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
148 (ULONG_PTR
)MemoryArea
->StartingAddress
;
149 Status
= STATUS_SUCCESS
;
150 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
154 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
155 Status
= STATUS_UNSUCCESSFUL
;
164 DPRINT1("Unsupported or unimplemented class: %lx\n", VirtualMemoryInformationClass
);
165 Status
= STATUS_INVALID_INFO_CLASS
;
171 MmUnlockAddressSpace(AddressSpace
);
172 ObDereferenceObject(Process
);
178 MiProtectVirtualMemory(IN PEPROCESS Process
,
179 IN OUT PVOID
*BaseAddress
,
180 IN OUT PSIZE_T NumberOfBytesToProtect
,
181 IN ULONG NewAccessProtection
,
182 OUT PULONG OldAccessProtection OPTIONAL
)
184 PMEMORY_AREA MemoryArea
;
185 PMMSUPPORT AddressSpace
;
186 ULONG OldAccessProtection_
;
189 *NumberOfBytesToProtect
=
190 PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) -
191 PAGE_ROUND_DOWN(*BaseAddress
);
192 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
194 AddressSpace
= &Process
->Vm
;
196 MmLockAddressSpace(AddressSpace
);
197 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
198 if (MemoryArea
== NULL
)
200 MmUnlockAddressSpace(AddressSpace
);
201 return STATUS_UNSUCCESSFUL
;
204 if (OldAccessProtection
== NULL
)
205 OldAccessProtection
= &OldAccessProtection_
;
207 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
209 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, *BaseAddress
,
210 *NumberOfBytesToProtect
, NewAccessProtection
,
211 OldAccessProtection
);
213 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
215 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, *BaseAddress
,
216 *NumberOfBytesToProtect
,
218 OldAccessProtection
);
222 /* FIXME: Should we return failure or success in this case? */
223 Status
= STATUS_CONFLICTING_ADDRESSES
;
226 MmUnlockAddressSpace(AddressSpace
);
233 MiMapLockedPagesInUserSpace(IN PMDL Mdl
,
235 IN MEMORY_CACHING_TYPE CacheType
,
236 IN PVOID BaseAddress
)
239 PPFN_NUMBER MdlPages
;
241 PEPROCESS CurrentProcess
;
245 LARGE_INTEGER BoundaryAddressMultiple
;
247 /* Calculate the number of pages required. */
248 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
249 PageCount
= PAGE_ROUND_UP(Mdl
->ByteCount
+ Mdl
->ByteOffset
) / PAGE_SIZE
;
251 /* Set default page protection */
252 Protect
= PAGE_READWRITE
;
253 if (CacheType
== MmNonCached
) Protect
|= PAGE_NOCACHE
;
255 BoundaryAddressMultiple
.QuadPart
= 0;
258 CurrentProcess
= PsGetCurrentProcess();
260 MmLockAddressSpace(&CurrentProcess
->Vm
);
261 Status
= MmCreateMemoryArea(&CurrentProcess
->Vm
,
262 MEMORY_AREA_MDL_MAPPING
,
264 PageCount
* PAGE_SIZE
,
269 BoundaryAddressMultiple
);
270 MmUnlockAddressSpace(&CurrentProcess
->Vm
);
271 if (!NT_SUCCESS(Status
))
273 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
)
278 /* Throw exception */
279 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
283 /* Set the virtual mappings for the MDL pages. */
284 if (Mdl
->MdlFlags
& MDL_IO_SPACE
)
287 Status
= MmCreateVirtualMappingUnsafe(CurrentProcess
,
296 Status
= MmCreateVirtualMapping(CurrentProcess
,
303 /* Check if the mapping suceeded */
304 if (!NT_SUCCESS(Status
))
306 /* If it can fail, return NULL */
307 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
) return NULL
;
309 /* Throw exception */
310 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
313 /* Return the base */
314 Base
= (PVOID
)((ULONG_PTR
)Base
+ Mdl
->ByteOffset
);
320 MiUnmapLockedPagesInUserSpace(IN PVOID BaseAddress
,
323 PMEMORY_AREA MemoryArea
;
326 ASSERT(Mdl
->Process
== PsGetCurrentProcess());
328 /* Find the memory area */
329 MemoryArea
= MmLocateMemoryAreaByAddress(&Mdl
->Process
->Vm
,
334 MmFreeMemoryArea(&Mdl
->Process
->Vm
,
340 /* SYSTEM CALLS ***************************************************************/
343 NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
345 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
346 OUT PVOID VirtualMemoryInformation
,
348 OUT PSIZE_T UnsafeResultLength
)
351 SIZE_T ResultLength
= 0;
352 KPROCESSOR_MODE PreviousMode
;
353 WCHAR ModuleFileNameBuffer
[MAX_PATH
] = {0};
354 UNICODE_STRING ModuleFileName
;
355 PMEMORY_SECTION_NAME SectionName
= NULL
;
359 MEMORY_BASIC_INFORMATION BasicInfo
;
363 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
364 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
365 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
366 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
367 Length
,ResultLength
);
369 PreviousMode
= ExGetPreviousMode();
371 if (PreviousMode
!= KernelMode
)
375 ProbeForWrite(VirtualMemoryInformation
,
379 if (UnsafeResultLength
) ProbeForWriteSize_t(UnsafeResultLength
);
381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
383 /* Return the exception code */
384 _SEH2_YIELD(return _SEH2_GetExceptionCode());
389 if (Address
>= MmSystemRangeStart
)
391 DPRINT1("Invalid parameter\n");
392 return STATUS_INVALID_PARAMETER
;
395 /* FIXME: Move this inside MiQueryVirtualMemory */
396 if (VirtualMemoryInformationClass
== MemorySectionName
)
398 Status
= ObReferenceObjectByHandle(ProcessHandle
,
399 PROCESS_QUERY_INFORMATION
,
405 if (!NT_SUCCESS(Status
))
407 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
411 RtlInitEmptyUnicodeString(&ModuleFileName
, ModuleFileNameBuffer
, sizeof(ModuleFileNameBuffer
));
412 Status
= MmGetFileNameForAddress(Address
, &ModuleFileName
);
414 if (NT_SUCCESS(Status
))
416 SectionName
= VirtualMemoryInformation
;
417 if (PreviousMode
!= KernelMode
)
421 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
422 SectionName
->SectionFileName
.MaximumLength
= Length
;
423 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
425 if (UnsafeResultLength
!= NULL
)
427 *UnsafeResultLength
= ModuleFileName
.Length
;
430 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
432 Status
= _SEH2_GetExceptionCode();
438 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
439 SectionName
->SectionFileName
.MaximumLength
= Length
;
440 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
442 if (UnsafeResultLength
!= NULL
)
444 *UnsafeResultLength
= ModuleFileName
.Length
;
448 ObDereferenceObject(Process
);
453 Status
= MiQueryVirtualMemory(ProcessHandle
,
455 VirtualMemoryInformationClass
,
461 if (NT_SUCCESS(Status
))
463 if (PreviousMode
!= KernelMode
)
467 if (ResultLength
> 0)
469 ProbeForWrite(VirtualMemoryInformation
,
472 RtlCopyMemory(VirtualMemoryInformation
,
476 if (UnsafeResultLength
!= NULL
)
478 *UnsafeResultLength
= ResultLength
;
481 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
483 Status
= _SEH2_GetExceptionCode();
489 if (ResultLength
> 0)
491 RtlCopyMemory(VirtualMemoryInformation
,
496 if (UnsafeResultLength
!= NULL
)
498 *UnsafeResultLength
= ResultLength
;