1 /* $Id: virtual.c,v 1.28 2000/05/13 13:51:06 dwelch Exp $
3 * COPYRIGHT: See COPYING in the top directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/virtual.c
6 * PURPOSE: implementing the Virtualxxx section of the win32 api
7 * PROGRAMMER: David Welch
10 * 10/6/98: Corrections from Fatahi (i_fatahi@hotmail.com)
11 * 30/9/98: Implemented ZwxxxVirtualMemory functions
14 /* INCLUDE *****************************************************************/
16 #include <ddk/ntddk.h>
17 #include <internal/mm.h>
18 #include <internal/mmhal.h>
19 #include <internal/ob.h>
20 #include <internal/io.h>
21 #include <internal/ps.h>
23 #include <internal/string.h>
26 #include <internal/debug.h>
28 /* FUNCTIONS ****************************************************************/
30 NTSTATUS
MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace
,
31 MEMORY_AREA
* MemoryArea
,
34 if (MmIsPagePresent(NULL
, Address
))
37 return(STATUS_SUCCESS
);
40 MmSetPage(PsGetCurrentProcess(),
42 MemoryArea
->Attributes
,
43 (ULONG
)MmAllocPage());
45 return(STATUS_SUCCESS
);
48 NTSTATUS
MmReleaseMemoryArea(PEPROCESS Process
, PMEMORY_AREA Marea
)
52 DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process
,Marea
);
54 DPRINT("Releasing %x between %x %x\n",
55 Marea
, Marea
->BaseAddress
, Marea
->BaseAddress
+ Marea
->Length
);
57 if (Marea
->Type
== MEMORY_AREA_SECTION_VIEW_COMMIT
||
58 Marea
->Type
== MEMORY_AREA_SECTION_VIEW_RESERVE
)
60 MmUnmapViewOfSection(Process
, Marea
);
63 for (i
= Marea
->BaseAddress
;
64 i
< (Marea
->BaseAddress
+ Marea
->Length
);
67 MmDeletePageEntry(Process
, i
, TRUE
);
71 return(STATUS_SUCCESS
);
74 NTSTATUS
MmReleaseMmInfo(PEPROCESS Process
)
76 PLIST_ENTRY CurrentEntry
;
79 DPRINT("MmReleaseMmInfo(Process %x)\n",Process
);
81 MmLockAddressSpace(&Process
->Pcb
.AddressSpace
);
83 while (!IsListEmpty(&Process
->Pcb
.AddressSpace
.MAreaListHead
))
85 CurrentEntry
= RemoveHeadList(
86 &Process
->Pcb
.AddressSpace
.MAreaListHead
);
87 Current
= CONTAINING_RECORD(CurrentEntry
, MEMORY_AREA
, Entry
);
89 MmReleaseMemoryArea(Process
, Current
);
92 Mmi386ReleaseMmInfo(Process
);
94 MmUnlockAddressSpace(&Process
->Pcb
.AddressSpace
);
96 DPRINT("Finished MmReleaseMmInfo()\n");
97 return(STATUS_SUCCESS
);
100 BOOLEAN STDCALL
MmIsNonPagedSystemAddressValid(PVOID VirtualAddress
)
105 BOOLEAN STDCALL
MmIsAddressValid(PVOID VirtualAddress
)
107 * FUNCTION: Checks whether the given address is valid for a read or write
109 * VirtualAddress = address to check
110 * RETURNS: True if the access would be valid
111 * False if the access would cause a page fault
112 * NOTES: This function checks whether a byte access to the page would
113 * succeed. Is this realistic for RISC processors which don't
114 * allow byte granular access?
117 MEMORY_AREA
* MemoryArea
;
118 PMADDRESS_SPACE AddressSpace
;
120 AddressSpace
= &PsGetCurrentProcess()->Pcb
.AddressSpace
;
122 MmLockAddressSpace(AddressSpace
);
123 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
126 if (MemoryArea
== NULL
)
128 MmUnlockAddressSpace(AddressSpace
);
131 MmUnlockAddressSpace(AddressSpace
);
136 NTSTATUS STDCALL
NtAllocateVirtualMemory(IN HANDLE ProcessHandle
,
137 IN OUT PVOID
* BaseAddress
,
139 IN OUT PULONG RegionSize
,
140 IN ULONG AllocationType
,
143 * FUNCTION: Allocates a block of virtual memory in the process address space
145 * ProcessHandle = The handle of the process which owns the virtual memory
146 * BaseAddress = A pointer to the virtual memory allocated. If you
147 * supply a non zero value the system will try to
148 * allocate the memory at the address supplied. It round
149 * it down to a multiple of the page size.
150 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
151 * that must be zero, ensuring that the memory will be
152 * allocated at a address below a certain value.
153 * RegionSize = The number of bytes to allocate
154 * AllocationType = Indicates the type of virtual memory you like to
155 * allocated, can be one of the values : MEM_COMMIT,
156 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
157 * Protect = Indicates the protection type of the pages allocated, can be
158 * a combination of PAGE_READONLY, PAGE_READWRITE,
159 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
162 * This function maps to the win32 VirtualAllocEx. Virtual memory is
163 * process based so the protocol starts with a ProcessHandle. I
164 * splitted the functionality of obtaining the actual address and
165 * specifying the start address in two parameters ( BaseAddress and
166 * StartAddress ) The NumberOfBytesAllocated specify the range and the
167 * AllocationType and ProctectionType map to the other two parameters.
172 MEMORY_AREA
* MemoryArea
;
175 PMADDRESS_SPACE AddressSpace
;
177 DPRINT("NtAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
178 "ZeroBits %d, *RegionSize %x, AllocationType %x, Protect %x)\n",
179 ProcessHandle
,*BaseAddress
,ZeroBits
,*RegionSize
,AllocationType
,
182 Status
= ObReferenceObjectByHandle(ProcessHandle
,
183 PROCESS_VM_OPERATION
,
188 if (Status
!= STATUS_SUCCESS
)
190 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
194 if (AllocationType
& MEM_RESERVE
)
196 Type
= MEMORY_AREA_RESERVE
;
200 Type
= MEMORY_AREA_COMMIT
;
203 AddressSpace
= &Process
->Pcb
.AddressSpace
;
204 MmLockAddressSpace(AddressSpace
);
206 if ((*BaseAddress
) != 0)
208 MemoryArea
= MmOpenMemoryAreaByAddress(&Process
->Pcb
.AddressSpace
,
211 if (MemoryArea
!= NULL
)
213 if (MemoryArea
->BaseAddress
== (*BaseAddress
) &&
214 MemoryArea
->Length
== *RegionSize
)
216 MemoryArea
->Type
= Type
;
217 MemoryArea
->Attributes
=Protect
;
218 DPRINT("*BaseAddress %x\n",*BaseAddress
);
219 MmUnlockAddressSpace(AddressSpace
);
220 ObDereferenceObject(Process
);
221 return(STATUS_SUCCESS
);
224 MemoryArea
= MmSplitMemoryArea(Process
,
225 &Process
->Pcb
.AddressSpace
,
231 DPRINT("*BaseAddress %x\n",*BaseAddress
);
232 MmUnlockAddressSpace(AddressSpace
);
233 ObDereferenceObject(Process
);
234 return(STATUS_SUCCESS
);
238 // FIXME RegionSize should be passed as pointer
241 Status
= MmCreateMemoryArea(Process
,
242 &Process
->Pcb
.AddressSpace
,
249 if (Status
!= STATUS_SUCCESS
)
251 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
252 MmUnlockAddressSpace(AddressSpace
);
253 ObDereferenceObject(Process
);
257 DPRINT("*BaseAddress %x\n",*BaseAddress
);
258 MmUnlockAddressSpace(AddressSpace
);
259 ObDereferenceObject(Process
);
260 return(STATUS_SUCCESS
);
264 NTSTATUS STDCALL
NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
265 IN PVOID BaseAddress
,
266 IN ULONG NumberOfBytesToFlush
,
267 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
269 * FUNCTION: Flushes virtual memory to file
271 * ProcessHandle = Points to the process that allocated the virtual
273 * BaseAddress = Points to the memory address
274 * NumberOfBytesToFlush = Limits the range to flush,
275 * NumberOfBytesFlushed = Actual number of bytes flushed
283 NTSTATUS STDCALL
NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
284 IN PVOID
* BaseAddress
,
285 IN PULONG RegionSize
,
288 * FUNCTION: Frees a range of virtual memory
290 * ProcessHandle = Points to the process that allocated the virtual
292 * BaseAddress = Points to the memory address, rounded down to a
293 * multiple of the pagesize
294 * RegionSize = Limits the range to free, rounded up to a multiple of
296 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
300 MEMORY_AREA
* MemoryArea
;
303 PMADDRESS_SPACE AddressSpace
;
305 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
306 "*RegionSize %x, FreeType %x)\n",ProcessHandle
,*BaseAddress
,
307 *RegionSize
,FreeType
);
310 Status
= ObReferenceObjectByHandle(ProcessHandle
,
311 PROCESS_VM_OPERATION
,
316 if (Status
!= STATUS_SUCCESS
)
321 AddressSpace
= &Process
->Pcb
.AddressSpace
;
323 MmLockAddressSpace(AddressSpace
);
324 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
326 if (MemoryArea
== NULL
)
328 MmUnlockAddressSpace(AddressSpace
);
329 ObDereferenceObject(Process
);
330 return(STATUS_UNSUCCESSFUL
);
336 if (MemoryArea
->BaseAddress
!= (*BaseAddress
))
338 MmUnlockAddressSpace(AddressSpace
);
339 ObDereferenceObject(Process
);
340 return(STATUS_UNSUCCESSFUL
);
342 MmFreeMemoryArea(&Process
->Pcb
.AddressSpace
,
346 MmUnlockAddressSpace(AddressSpace
);
347 ObDereferenceObject(Process
);
348 return(STATUS_SUCCESS
);
351 MmSplitMemoryArea(Process
,
352 &Process
->Pcb
.AddressSpace
,
357 MemoryArea
->Attributes
);
358 MmUnlockAddressSpace(AddressSpace
);
359 ObDereferenceObject(Process
);
360 return(STATUS_SUCCESS
);
362 MmUnlockAddressSpace(AddressSpace
);
363 ObDereferenceObject(Process
);
364 return(STATUS_NOT_IMPLEMENTED
);
368 NTSTATUS STDCALL
NtLockVirtualMemory(HANDLE ProcessHandle
,
370 ULONG NumberOfBytesToLock
,
371 PULONG NumberOfBytesLocked
)
377 VOID
MmChangeAreaProtection(PEPROCESS Process
,
384 for (i
=0; i
<(Length
/PAGESIZE
); i
++)
386 if (MmIsPagePresent(Process
, BaseAddress
+ (i
*PAGESIZE
)))
388 MmSetPageProtect(Process
,
389 BaseAddress
+ (i
*PAGESIZE
),
396 NTSTATUS STDCALL
NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
397 IN PVOID BaseAddress
,
398 IN ULONG NumberOfBytesToProtect
,
399 IN ULONG NewAccessProtection
,
400 OUT PULONG OldAccessProtection
)
402 PMEMORY_AREA MemoryArea
;
405 PMADDRESS_SPACE AddressSpace
;
407 Status
= ObReferenceObjectByHandle(ProcessHandle
,
408 PROCESS_VM_OPERATION
,
413 if (Status
!= STATUS_SUCCESS
)
415 DPRINT("NtProtectVirtualMemory() = %x\n",Status
);
419 AddressSpace
= &Process
->Pcb
.AddressSpace
;
421 MmLockAddressSpace(AddressSpace
);
422 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
424 if (MemoryArea
== NULL
)
426 DPRINT("NtProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL
);
427 MmUnlockAddressSpace(AddressSpace
);
428 ObDereferenceObject(Process
);
429 return(STATUS_UNSUCCESSFUL
);
432 *OldAccessProtection
= MemoryArea
->Attributes
;
434 if (MemoryArea
->BaseAddress
== BaseAddress
&&
435 MemoryArea
->Length
== NumberOfBytesToProtect
)
437 MemoryArea
->Attributes
= NewAccessProtection
;
441 MemoryArea
= MmSplitMemoryArea(Process
,
442 &Process
->Pcb
.AddressSpace
,
445 NumberOfBytesToProtect
,
447 NewAccessProtection
);
449 MmChangeAreaProtection(Process
,
451 NumberOfBytesToProtect
,
452 NewAccessProtection
);
453 MmUnlockAddressSpace(AddressSpace
);
454 ObDereferenceObject(Process
);
455 return(STATUS_SUCCESS
);
459 NTSTATUS STDCALL
NtQueryVirtualMemory (IN HANDLE ProcessHandle
,
461 IN CINT VirtualMemoryInformationClass
,
462 OUT PVOID VirtualMemoryInformation
,
464 OUT PULONG ResultLength
)
468 MEMORY_AREA
* MemoryArea
;
470 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
471 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
472 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
473 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
474 Length
,ResultLength
);
476 switch(VirtualMemoryInformationClass
)
478 case MemoryBasicInformation
:
480 PMEMORY_BASIC_INFORMATION Info
=
481 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
482 PMADDRESS_SPACE AddressSpace
;
484 if (Length
< sizeof(MEMORY_BASIC_INFORMATION
))
486 ObDereferenceObject(Process
);
487 return STATUS_INFO_LENGTH_MISMATCH
;
492 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
495 Status
= ObReferenceObjectByHandle(ProcessHandle
,
496 PROCESS_QUERY_INFORMATION
,
502 if (!NT_SUCCESS(Status
))
504 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
508 AddressSpace
= &Process
->Pcb
.AddressSpace
;
509 MmLockAddressSpace(AddressSpace
);
510 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
513 if (MemoryArea
== NULL
)
515 Info
->State
= MEM_FREE
;
516 DPRINT("Virtual memory at %p is free.\n", Address
);
517 MmUnlockAddressSpace(AddressSpace
);
518 ObDereferenceObject(Process
);
519 return (STATUS_SUCCESS
);
522 if (MemoryArea
->Type
== MEMORY_AREA_COMMIT
)
524 Info
->State
= MEM_COMMIT
;
528 Info
->State
= MEM_RESERVE
;
531 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
532 Info
->RegionSize
= MemoryArea
->Length
;
534 DPRINT("BaseAddress %p, RegionSize %x State %x\n",
535 Info
->BaseAddress
, Info
->RegionSize
, Info
->State
);
537 MmUnlockAddressSpace(AddressSpace
);
538 ObDereferenceObject(Process
);
539 return STATUS_SUCCESS
;
544 return STATUS_INVALID_INFO_CLASS
;
548 NTSTATUS STDCALL
NtReadVirtualMemory(IN HANDLE ProcessHandle
,
549 IN PVOID BaseAddress
,
551 IN ULONG NumberOfBytesToRead
,
552 OUT PULONG NumberOfBytesRead
)
559 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
560 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle
,BaseAddress
,
561 Buffer
,NumberOfBytesToRead
);
563 Status
= ObReferenceObjectByHandle(ProcessHandle
,
569 if (Status
!= STATUS_SUCCESS
)
574 Mdl
= MmCreateMdl(NULL
,
576 NumberOfBytesToRead
);
577 MmProbeAndLockPages(Mdl
,
581 KeAttachProcess(Process
);
583 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
584 memcpy(SystemAddress
, BaseAddress
, NumberOfBytesToRead
);
588 ObDereferenceObject(Process
);
590 *NumberOfBytesRead
= NumberOfBytesToRead
;
591 return(STATUS_SUCCESS
);
595 NTSTATUS STDCALL
NtUnlockVirtualMemory(HANDLE ProcessHandle
,
597 ULONG NumberOfBytesToUnlock
,
598 PULONG NumberOfBytesUnlocked OPTIONAL
)
604 NTSTATUS STDCALL
NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
605 IN PVOID BaseAddress
,
607 IN ULONG NumberOfBytesToWrite
,
608 OUT PULONG NumberOfBytesWritten
)
615 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
616 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle
,BaseAddress
,
617 Buffer
,NumberOfBytesToWrite
);
619 Status
= ObReferenceObjectByHandle(ProcessHandle
,
625 if (Status
!= STATUS_SUCCESS
)
630 Mdl
= MmCreateMdl(NULL
,
632 NumberOfBytesToWrite
);
633 MmProbeAndLockPages(Mdl
,
637 KeAttachProcess(Process
);
639 DPRINT("Attached to process copying memory\n");
641 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
642 memcpy(BaseAddress
, SystemAddress
, NumberOfBytesToWrite
);
644 DPRINT("Done copy\n");
648 ObDereferenceObject(Process
);
650 *NumberOfBytesWritten
= NumberOfBytesToWrite
;
652 DPRINT("Finished NtWriteVirtualMemory()\n");
654 return(STATUS_SUCCESS
);
660 MmSecureVirtualMemory (
673 MmUnsecureVirtualMemory (