2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/virtual.c
5 * PURPOSE: implementing the Virtualxxx section of the win32 api
6 * PROGRAMMER: David Welch
9 * 10/6/98: Corrections from Fatahi (i_fatahi@hotmail.com)
10 * 30/9/98: Implemented ZwxxxVirtualMemory functions
13 /* INCLUDE *****************************************************************/
17 #include <internal/i386/segment.h>
18 #include <internal/mm.h>
19 #include <internal/mmhal.h>
20 #include <internal/ob.h>
21 #include <internal/io.h>
22 #include <internal/ps.h>
25 #include <internal/debug.h>
27 /* TYPES *******************************************************************/
29 extern unsigned int etext
;
30 extern unsigned int end
;
32 static MEMORY_AREA
* kernel_text_desc
= NULL
;
33 static MEMORY_AREA
* kernel_data_desc
= NULL
;
34 static MEMORY_AREA
* kernel_param_desc
= NULL
;
35 static MEMORY_AREA
* kernel_pool_desc
= NULL
;
37 /* FUNCTIONS ****************************************************************/
39 void VirtualInit(boot_param
* bp
)
41 * FUNCTION: Intialize the memory areas list
43 * bp = Pointer to the boot parameters
44 * kernel_len = Length of the kernel
47 unsigned int kernel_len
= bp
->end_mem
- bp
->start_mem
;
50 ULONG ParamLength
= kernel_len
;
52 DPRINT("VirtualInit() %x\n",bp
);
55 ExInitNonPagedPool(KERNEL_BASE
+ PAGE_ROUND_UP(kernel_len
) + PAGESIZE
);
59 * Setup the system area descriptor list
61 BaseAddress
= (PVOID
)KERNEL_BASE
;
62 Length
= PAGE_ROUND_UP(((ULONG
)&etext
)) - KERNEL_BASE
;
63 ParamLength
= ParamLength
- Length
;
64 MmCreateMemoryArea(KernelMode
,NULL
,MEMORY_AREA_SYSTEM
,&BaseAddress
,
65 Length
,0,&kernel_text_desc
);
67 Length
= PAGE_ROUND_UP(((ULONG
)&end
)) - PAGE_ROUND_UP(((ULONG
)&etext
));
68 ParamLength
= ParamLength
- Length
;
69 DPRINT("Length %x\n",Length
);
70 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG
)&etext
));
71 MmCreateMemoryArea(KernelMode
,
80 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG
)&end
));
82 MmCreateMemoryArea(KernelMode
,NULL
,MEMORY_AREA_SYSTEM
,&BaseAddress
,
83 Length
,0,&kernel_param_desc
);
85 BaseAddress
= (PVOID
)(KERNEL_BASE
+ PAGE_ROUND_UP(kernel_len
) + PAGESIZE
);
86 Length
= NONPAGED_POOL_SIZE
;
87 MmCreateMemoryArea(KernelMode
,NULL
,MEMORY_AREA_SYSTEM
,&BaseAddress
,
88 Length
,0,&kernel_pool_desc
);
90 // MmDumpMemoryAreas();
93 MmInitSectionImplementation();
96 ULONG
MmCommitedSectionHandleFault(MEMORY_AREA
* MemoryArea
, ULONG Address
)
98 MmSetPage(PsGetCurrentProcess(),
100 MemoryArea
->Attributes
,
105 NTSTATUS
MmSectionHandleFault(MEMORY_AREA
* MemoryArea
, PVOID Address
)
107 LARGE_INTEGER Offset
;
108 IO_STATUS_BLOCK IoStatus
;
110 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
115 MemoryArea
->Attributes
,
118 LARGE_INTEGER_QUAD_PART(Offset
) = (Address
- MemoryArea
->BaseAddress
) +
119 MemoryArea
->Data
.SectionData
.ViewOffset
;
121 DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
122 MemoryArea
->Data
.SectionData
.Section
->FileObject
);
124 if (MemoryArea
->Data
.SectionData
.Section
->FileObject
== NULL
)
126 return(STATUS_UNSUCCESSFUL
);
129 IoPageRead(MemoryArea
->Data
.SectionData
.Section
->FileObject
,
134 DPRINT("Returning from MmSectionHandleFault()\n");
136 return(STATUS_SUCCESS
);
139 asmlinkage
int page_fault_handler(unsigned int cs
,
142 * FUNCTION: Handle a page fault
145 KPROCESSOR_MODE FaultMode
;
146 MEMORY_AREA
* MemoryArea
;
151 * Get the address for the page fault
154 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
155 DPRINT("Page fault at address %x with eip %x\n",cr2
,eip
);
157 cr2
= PAGE_ROUND_DOWN(cr2
);
159 if (KeGetCurrentIrql()!=PASSIVE_LEVEL
)
161 DbgPrint("Page fault at high IRQL\n");
166 KeRaiseIrql(DISPATCH_LEVEL
,&oldlvl
);
169 * Find the memory area for the faulting address
171 if (cr2
>=KERNEL_BASE
)
178 printk("%s:%d\n",__FILE__
,__LINE__
);
181 FaultMode
= UserMode
;
185 FaultMode
= KernelMode
;
188 MemoryArea
= MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID
)cr2
);
189 if (MemoryArea
==NULL
)
191 printk("%s:%d\n",__FILE__
,__LINE__
);
195 switch (MemoryArea
->Type
)
197 case MEMORY_AREA_SYSTEM
:
201 case MEMORY_AREA_SECTION_VIEW_COMMIT
:
202 if (MmSectionHandleFault(MemoryArea
, (PVOID
)cr2
)==STATUS_SUCCESS
)
212 case MEMORY_AREA_COMMIT
:
213 stat
= MmCommitedSectionHandleFault(MemoryArea
,cr2
);
227 BOOLEAN
MmIsNonPagedSystemAddressValid(PVOID VirtualAddress
)
232 BOOLEAN
MmIsAddressValid(PVOID VirtualAddress
)
234 * FUNCTION: Checks whether the given address is valid for a read or write
236 * VirtualAddress = address to check
237 * RETURNS: True if the access would be valid
238 * False if the access would cause a page fault
239 * NOTES: This function checks whether a byte access to the page would
240 * succeed. Is this realistic for RISC processors which don't
241 * allow byte granular access?
244 MEMORY_AREA
* MemoryArea
;
246 MemoryArea
= MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),
249 if (MemoryArea
== NULL
)
258 NtAllocateVirtualMemory(
259 IN HANDLE ProcessHandle
,
260 IN OUT PVOID
*BaseAddress
,
262 IN OUT PULONG RegionSize
,
263 IN ULONG AllocationType
,
267 return(ZwAllocateVirtualMemory(ProcessHandle
,
277 ZwAllocateVirtualMemory(
278 IN HANDLE ProcessHandle
,
279 IN OUT PVOID
*BaseAddress
,
281 IN OUT PULONG RegionSize
,
282 IN ULONG AllocationType
,
286 * FUNCTION: Allocates a block of virtual memory in the process address space
288 * ProcessHandle = The handle of the process which owns the virtual memory
289 * BaseAddress = A pointer to the virtual memory allocated. If you
290 * supply a non zero value the system will try to
291 * allocate the memory at the address supplied. It round
292 * it down to a multiple of the page size.
293 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
294 * that must be zero, ensuring that the memory will be
295 * allocated at a address below a certain value.
296 * RegionSize = The number of bytes to allocate
297 * AllocationType = Indicates the type of virtual memory you like to
298 * allocated, can be one of the values : MEM_COMMIT,
299 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
300 * Protect = Indicates the protection type of the pages allocated, can be
301 * a combination of PAGE_READONLY, PAGE_READWRITE,
302 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
305 * This function maps to the win32 VirtualAllocEx. Virtual memory is
306 * process based so the protocol starts with a ProcessHandle. I
307 * splitted the functionality of obtaining the actual address and
308 * specifying the start address in two parameters ( BaseAddress and
309 * StartAddress ) The NumberOfBytesAllocated specify the range and the
310 * AllocationType and ProctectionType map to the other two parameters.
315 MEMORY_AREA
* MemoryArea
;
319 DPRINT("ZwAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
320 "ZeroBits %d, RegionSize %d, AllocationType %x, Protect %x)\n",
321 ProcessHandle
,*BaseAddress
,ZeroBits
,*RegionSize
,AllocationType
,
324 Status
= ObReferenceObjectByHandle(ProcessHandle
,
325 PROCESS_VM_OPERATION
,
330 if (Status
!= STATUS_SUCCESS
)
332 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status
);
336 if (AllocationType
& MEM_RESERVE
)
338 Type
= MEMORY_AREA_RESERVE
;
342 Type
= MEMORY_AREA_COMMIT
;
345 if ((*BaseAddress
) != 0)
347 MemoryArea
= MmOpenMemoryAreaByAddress(Process
, *BaseAddress
);
349 if (MemoryArea
!= NULL
)
351 if (MemoryArea
->BaseAddress
== (*BaseAddress
) &&
352 MemoryArea
->Length
== *RegionSize
)
354 MemoryArea
->Type
= Type
;
355 MemoryArea
->Attributes
=Protect
;
356 DPRINT("*BaseAddress %x\n",*BaseAddress
);
357 return(STATUS_SUCCESS
);
360 MemoryArea
= MmSplitMemoryArea(Process
,
366 DPRINT("*BaseAddress %x\n",*BaseAddress
);
367 return(STATUS_SUCCESS
);
371 //FIXME RegionSize should be passed as pointer
374 Status
= MmCreateMemoryArea(UserMode
,
382 if (Status
!= STATUS_SUCCESS
)
384 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status
);
388 DPRINT("*BaseAddress %x\n",*BaseAddress
);
390 return(STATUS_SUCCESS
);
393 NTSTATUS STDCALL
NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
394 IN PVOID BaseAddress
,
395 IN ULONG NumberOfBytesToFlush
,
396 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
398 return(ZwFlushVirtualMemory(ProcessHandle
,
400 NumberOfBytesToFlush
,
401 NumberOfBytesFlushed
));
404 NTSTATUS STDCALL
ZwFlushVirtualMemory(IN HANDLE ProcessHandle
,
405 IN PVOID BaseAddress
,
406 IN ULONG NumberOfBytesToFlush
,
407 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
410 * FUNCTION: Flushes virtual memory to file
412 * ProcessHandle = Points to the process that allocated the virtual
414 * BaseAddress = Points to the memory address
415 * NumberOfBytesToFlush = Limits the range to flush,
416 * NumberOfBytesFlushed = Actual number of bytes flushed
423 NTSTATUS STDCALL
NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
424 IN PVOID
*BaseAddress
,
425 IN PULONG RegionSize
,
428 return(ZwFreeVirtualMemory(ProcessHandle
,
434 NTSTATUS STDCALL
ZwFreeVirtualMemory(IN HANDLE ProcessHandle
,
435 IN PVOID
*BaseAddress
,
436 IN PULONG RegionSize
,
440 * FUNCTION: Frees a range of virtual memory
442 * ProcessHandle = Points to the process that allocated the virtual
444 * BaseAddress = Points to the memory address, rounded down to a
445 * multiple of the pagesize
446 * RegionSize = Limits the range to free, rounded up to a multiple of
448 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
452 MEMORY_AREA
* MemoryArea
;
456 Status
= ObReferenceObjectByHandle(ProcessHandle
,
457 PROCESS_VM_OPERATION
,
462 if (Status
!= STATUS_SUCCESS
)
467 MemoryArea
= MmOpenMemoryAreaByAddress(Process
,*BaseAddress
);
468 if (MemoryArea
== NULL
)
470 return(STATUS_UNSUCCESSFUL
);
476 if (MemoryArea
->BaseAddress
!= (*BaseAddress
))
478 return(STATUS_UNSUCCESSFUL
);
480 MmFreeMemoryArea(PsGetCurrentProcess(),
484 return(STATUS_SUCCESS
);
487 MmSplitMemoryArea(PsGetCurrentProcess(),
492 MemoryArea
->Attributes
);
493 return(STATUS_SUCCESS
);
496 return(STATUS_NOT_IMPLEMENTED
);
499 NTSTATUS STDCALL
NtLockVirtualMemory(HANDLE ProcessHandle
,
501 ULONG NumberOfBytesToLock
,
502 PULONG NumberOfBytesLocked
)
504 return(ZwLockVirtualMemory(ProcessHandle
,
507 NumberOfBytesLocked
));
510 NTSTATUS STDCALL
ZwLockVirtualMemory(HANDLE ProcessHandle
,
512 ULONG NumberOfBytesToLock
,
513 PULONG NumberOfBytesLocked
)
518 NTSTATUS STDCALL
NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
519 IN PVOID BaseAddress
,
520 IN ULONG NumberOfBytesToProtect
,
521 IN ULONG NewAccessProtection
,
522 OUT PULONG OldAccessProtection
)
524 return(ZwProtectVirtualMemory(ProcessHandle
,
526 NumberOfBytesToProtect
,
528 OldAccessProtection
));
531 VOID
MmChangeAreaProtection(PEPROCESS Process
,
538 for (i
=0; i
<(Length
/PAGESIZE
); i
++)
540 if (MmIsPagePresent(Process
, BaseAddress
+ (i
*PAGESIZE
)))
542 MmSetPageProtect(Process
, BaseAddress
+ (i
*PAGESIZE
), Protect
);
547 NTSTATUS STDCALL
ZwProtectVirtualMemory(IN HANDLE ProcessHandle
,
548 IN PVOID BaseAddress
,
549 IN ULONG NumberOfBytesToProtect
,
550 IN ULONG NewAccessProtection
,
551 OUT PULONG OldAccessProtection
)
553 PMEMORY_AREA MemoryArea
;
557 Status
= ObReferenceObjectByHandle(ProcessHandle
,
558 PROCESS_VM_OPERATION
,
563 if (Status
!= STATUS_SUCCESS
)
565 DbgPrint("ZwProtectVirtualMemory() = %x\n",Status
);
569 MemoryArea
= MmOpenMemoryAreaByAddress(Process
,BaseAddress
);
570 if (MemoryArea
== NULL
)
572 DbgPrint("ZwProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL
);
573 return(STATUS_UNSUCCESSFUL
);
576 *OldAccessProtection
= MemoryArea
->Attributes
;
578 if (MemoryArea
->BaseAddress
== BaseAddress
&&
579 MemoryArea
->Length
== NumberOfBytesToProtect
)
581 MemoryArea
->Attributes
= NewAccessProtection
;
585 MemoryArea
= MmSplitMemoryArea(Process
,
588 NumberOfBytesToProtect
,
590 NewAccessProtection
);
592 MmChangeAreaProtection(Process
,BaseAddress
,NumberOfBytesToProtect
,
593 NewAccessProtection
);
594 return(STATUS_SUCCESS
);
598 NTSTATUS STDCALL
NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
600 IN IN CINT VirtualMemoryInformationClass
,
601 OUT PVOID VirtualMemoryInformation
,
603 OUT PULONG ResultLength
)
605 return(ZwQueryVirtualMemory(ProcessHandle
,
607 VirtualMemoryInformationClass
,
608 VirtualMemoryInformation
,
613 NTSTATUS STDCALL
ZwQueryVirtualMemory(IN HANDLE ProcessHandle
,
615 IN CINT VirtualMemoryInformationClass
,
616 OUT PVOID VirtualMemoryInformation
,
618 OUT PULONG ResultLength
)
623 NTSTATUS STDCALL
NtReadVirtualMemory(IN HANDLE ProcessHandle
,
624 IN PVOID BaseAddress
,
626 IN ULONG NumberOfBytesToRead
,
627 OUT PULONG NumberOfBytesRead
)
629 return(ZwReadVirtualMemory(ProcessHandle
,
636 NTSTATUS STDCALL
ZwReadVirtualMemory(IN HANDLE ProcessHandle
,
637 IN PVOID BaseAddress
,
639 IN ULONG NumberOfBytesToRead
,
640 OUT PULONG NumberOfBytesRead
)
643 MEMORY_AREA
* MemoryArea
;
648 Status
= ObReferenceObjectByHandle(ProcessHandle
,
654 if (Status
!= STATUS_SUCCESS
)
659 MemoryArea
= MmOpenMemoryAreaByAddress(Process
,BaseAddress
);
661 if (MemoryArea
== NULL
)
663 return(STATUS_UNSUCCESSFUL
);
665 if (MemoryArea
->Length
> NumberOfBytesToRead
)
667 NumberOfBytesToRead
= MemoryArea
->Length
;
670 *NumberOfBytesRead
= NumberOfBytesToRead
;
672 for (i
=0; i
<(NumberOfBytesToRead
/PAGESIZE
); i
++)
674 CurrentEntry
= MmGetPageEntry(Process
, (DWORD
)BaseAddress
+ (i
*PAGESIZE
));
675 RtlCopyMemory(Buffer
+ (i
*PAGESIZE
),
676 (PVOID
)physical_to_linear(PAGE_MASK(*CurrentEntry
)),
680 return(STATUS_SUCCESS
);
683 NTSTATUS STDCALL
NtUnlockVirtualMemory(HANDLE ProcessHandle
,
685 ULONG NumberOfBytesToUnlock
,
686 PULONG NumberOfBytesUnlocked OPTIONAL
)
688 return(ZwUnlockVirtualMemory(ProcessHandle
,
690 NumberOfBytesToUnlock
,
691 NumberOfBytesUnlocked
));
694 NTSTATUS STDCALL
ZwUnlockVirtualMemory(HANDLE ProcessHandle
,
696 ULONG NumberOfBytesToUnlock
,
697 PULONG NumberOfBytesUnlocked OPTIONAL
)
702 NTSTATUS STDCALL
NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
703 IN PVOID BaseAddress
,
705 IN ULONG NumberOfBytesToWrite
,
706 OUT PULONG NumberOfBytesWritten
)
708 return(ZwWriteVirtualMemory(ProcessHandle
,
711 NumberOfBytesToWrite
,
712 NumberOfBytesWritten
));
715 NTSTATUS STDCALL
ZwWriteVirtualMemory(IN HANDLE ProcessHandle
,
716 IN PVOID BaseAddress
,
718 IN ULONG NumberOfBytesToWrite
,
719 OUT PULONG NumberOfBytesWritten
)
722 PMEMORY_AREA InMemoryArea
;
723 PMEMORY_AREA OutMemoryArea
;
728 DPRINT("ZwWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
729 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle
,BaseAddress
,
730 Buffer
,NumberOfBytesToWrite
);
732 Status
= ObReferenceObjectByHandle(ProcessHandle
,
738 if (Status
!= STATUS_SUCCESS
)
743 OutMemoryArea
= MmOpenMemoryAreaByAddress(Process
,BaseAddress
);
744 if (OutMemoryArea
== NULL
)
746 return(STATUS_UNSUCCESSFUL
);
749 *NumberOfBytesWritten
= NumberOfBytesToWrite
;
751 DPRINT("*Buffer %x\n",((PULONG
)Buffer
)[0]);
753 for (i
=0; i
<(PAGE_ROUND_DOWN(NumberOfBytesToWrite
)/PAGESIZE
); i
++)
755 if (!MmIsPagePresent(Process
, BaseAddress
+ (i
*PAGESIZE
)))
757 DPRINT("OutMemoryArea->Attributes %x\n",
758 OutMemoryArea
->Attributes
);
760 BaseAddress
+ (i
*PAGESIZE
),
761 OutMemoryArea
->Attributes
,
764 CurrentEntry
= MmGetPageEntry(Process
, (DWORD
)BaseAddress
+
766 RtlCopyMemory((PVOID
)physical_to_linear(PAGE_MASK(*CurrentEntry
)) +
767 (((DWORD
)BaseAddress
)%PAGESIZE
),
768 Buffer
+ (i
*PAGESIZE
),
771 if ((NumberOfBytesToWrite
% PAGESIZE
) != 0)
773 if (!MmIsPagePresent(Process
, BaseAddress
+ (i
*PAGESIZE
)))
776 BaseAddress
+ (i
*PAGESIZE
),
777 OutMemoryArea
->Attributes
,
780 CurrentEntry
= MmGetPageEntry(Process
,
781 BaseAddress
+ (i
*PAGESIZE
));
783 physical_to_linear(PAGE_MASK(*CurrentEntry
)) +
784 (((DWORD
)BaseAddress
)%PAGESIZE
));
785 RtlCopyMemory((PVOID
)physical_to_linear(PAGE_MASK(*CurrentEntry
)) +
786 (((DWORD
)BaseAddress
)%PAGESIZE
),
787 Buffer
+ (i
*PAGESIZE
),
788 NumberOfBytesToWrite
% PAGESIZE
);
790 return(STATUS_SUCCESS
);