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 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
82 case MEMORY_AREA_SECTION_VIEW
:
83 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
88 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
89 Status
= STATUS_UNSUCCESSFUL
;
98 DPRINT1("Unsupported or unimplemented class: %lx\n", VirtualMemoryInformationClass
);
99 Status
= STATUS_INVALID_INFO_CLASS
;
105 MmUnlockAddressSpace(AddressSpace
);
106 ObDereferenceObject(Process
);
112 MiProtectVirtualMemory(IN PEPROCESS Process
,
113 IN OUT PVOID
*BaseAddress
,
114 IN OUT PSIZE_T NumberOfBytesToProtect
,
115 IN ULONG NewAccessProtection
,
116 OUT PULONG OldAccessProtection OPTIONAL
)
118 PMEMORY_AREA MemoryArea
;
119 PMMSUPPORT AddressSpace
;
120 ULONG OldAccessProtection_
;
123 *NumberOfBytesToProtect
=
124 PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) -
125 PAGE_ROUND_DOWN(*BaseAddress
);
126 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
128 AddressSpace
= &Process
->Vm
;
130 MmLockAddressSpace(AddressSpace
);
131 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
132 if (MemoryArea
== NULL
)
134 MmUnlockAddressSpace(AddressSpace
);
135 return STATUS_UNSUCCESSFUL
;
138 if (OldAccessProtection
== NULL
)
139 OldAccessProtection
= &OldAccessProtection_
;
141 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
143 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, *BaseAddress
,
144 *NumberOfBytesToProtect
, NewAccessProtection
,
145 OldAccessProtection
);
147 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
149 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, *BaseAddress
,
150 *NumberOfBytesToProtect
,
152 OldAccessProtection
);
156 /* FIXME: Should we return failure or success in this case? */
157 Status
= STATUS_CONFLICTING_ADDRESSES
;
160 MmUnlockAddressSpace(AddressSpace
);
167 MiMapLockedPagesInUserSpace(IN PMDL Mdl
,
169 IN MEMORY_CACHING_TYPE CacheType
,
170 IN PVOID BaseAddress
)
173 PPFN_NUMBER MdlPages
;
175 PEPROCESS CurrentProcess
;
179 LARGE_INTEGER BoundaryAddressMultiple
;
181 /* Calculate the number of pages required. */
182 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
183 PageCount
= PAGE_ROUND_UP(Mdl
->ByteCount
+ Mdl
->ByteOffset
) / PAGE_SIZE
;
185 /* Set default page protection */
186 Protect
= PAGE_READWRITE
;
187 if (CacheType
== MmNonCached
) Protect
|= PAGE_NOCACHE
;
189 BoundaryAddressMultiple
.QuadPart
= 0;
192 CurrentProcess
= PsGetCurrentProcess();
194 MmLockAddressSpace(&CurrentProcess
->Vm
);
195 Status
= MmCreateMemoryArea(&CurrentProcess
->Vm
,
196 MEMORY_AREA_MDL_MAPPING
,
198 PageCount
* PAGE_SIZE
,
203 BoundaryAddressMultiple
);
204 MmUnlockAddressSpace(&CurrentProcess
->Vm
);
205 if (!NT_SUCCESS(Status
))
207 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
)
212 /* Throw exception */
213 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
217 /* Set the virtual mappings for the MDL pages. */
218 if (Mdl
->MdlFlags
& MDL_IO_SPACE
)
221 Status
= MmCreateVirtualMappingUnsafe(CurrentProcess
,
230 Status
= MmCreateVirtualMapping(CurrentProcess
,
237 /* Check if the mapping suceeded */
238 if (!NT_SUCCESS(Status
))
240 /* If it can fail, return NULL */
241 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
) return NULL
;
243 /* Throw exception */
244 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
247 /* Return the base */
248 Base
= (PVOID
)((ULONG_PTR
)Base
+ Mdl
->ByteOffset
);
254 MiUnmapLockedPagesInUserSpace(IN PVOID BaseAddress
,
257 PMEMORY_AREA MemoryArea
;
260 ASSERT(Mdl
->Process
== PsGetCurrentProcess());
262 /* Find the memory area */
263 MemoryArea
= MmLocateMemoryAreaByAddress(&Mdl
->Process
->Vm
,
268 MmFreeMemoryArea(&Mdl
->Process
->Vm
,
274 /* SYSTEM CALLS ***************************************************************/
277 NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
279 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
280 OUT PVOID VirtualMemoryInformation
,
282 OUT PSIZE_T UnsafeResultLength
)
285 SIZE_T ResultLength
= 0;
286 KPROCESSOR_MODE PreviousMode
;
287 WCHAR ModuleFileNameBuffer
[MAX_PATH
] = {0};
288 UNICODE_STRING ModuleFileName
;
289 PMEMORY_SECTION_NAME SectionName
= NULL
;
293 MEMORY_BASIC_INFORMATION BasicInfo
;
297 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
298 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
299 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
300 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
301 Length
,ResultLength
);
303 PreviousMode
= ExGetPreviousMode();
305 if (PreviousMode
!= KernelMode
)
309 ProbeForWrite(VirtualMemoryInformation
,
313 if (UnsafeResultLength
) ProbeForWriteSize_t(UnsafeResultLength
);
315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
317 /* Return the exception code */
318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
323 if (Address
>= MmSystemRangeStart
)
325 DPRINT1("Invalid parameter\n");
326 return STATUS_INVALID_PARAMETER
;
329 /* FIXME: Move this inside MiQueryVirtualMemory */
330 if (VirtualMemoryInformationClass
== MemorySectionName
)
332 Status
= ObReferenceObjectByHandle(ProcessHandle
,
333 PROCESS_QUERY_INFORMATION
,
339 if (!NT_SUCCESS(Status
))
341 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
345 RtlInitEmptyUnicodeString(&ModuleFileName
, ModuleFileNameBuffer
, sizeof(ModuleFileNameBuffer
));
346 Status
= MmGetFileNameForAddress(Address
, &ModuleFileName
);
348 if (NT_SUCCESS(Status
))
350 SectionName
= VirtualMemoryInformation
;
351 if (PreviousMode
!= KernelMode
)
355 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
356 SectionName
->SectionFileName
.MaximumLength
= Length
;
357 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
359 if (UnsafeResultLength
!= NULL
)
361 *UnsafeResultLength
= ModuleFileName
.Length
;
364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
366 Status
= _SEH2_GetExceptionCode();
372 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
373 SectionName
->SectionFileName
.MaximumLength
= Length
;
374 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
376 if (UnsafeResultLength
!= NULL
)
378 *UnsafeResultLength
= ModuleFileName
.Length
;
382 ObDereferenceObject(Process
);
387 Status
= MiQueryVirtualMemory(ProcessHandle
,
389 VirtualMemoryInformationClass
,
395 if (NT_SUCCESS(Status
))
397 if (PreviousMode
!= KernelMode
)
401 if (ResultLength
> 0)
403 ProbeForWrite(VirtualMemoryInformation
,
406 RtlCopyMemory(VirtualMemoryInformation
,
410 if (UnsafeResultLength
!= NULL
)
412 *UnsafeResultLength
= ResultLength
;
415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
417 Status
= _SEH2_GetExceptionCode();
423 if (ResultLength
> 0)
425 RtlCopyMemory(VirtualMemoryInformation
,
430 if (UnsafeResultLength
!= NULL
)
432 *UnsafeResultLength
= ResultLength
;