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 set_page(Address
,0x7,get_free_page());
102 NTSTATUS
MmSectionHandleFault(MEMORY_AREA
* MemoryArea
, PVOID Address
)
104 LARGE_INTEGER Offset
;
105 IO_STATUS_BLOCK IoStatus
;
107 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
110 set_page((DWORD
)Address
,0x7,get_free_page());
112 LARGE_INTEGER_QUAD_PART(Offset
) = (Address
- MemoryArea
->BaseAddress
) +
113 MemoryArea
->Data
.SectionData
.ViewOffset
;
115 DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
116 MemoryArea
->Data
.SectionData
.Section
->FileObject
);
118 if (MemoryArea
->Data
.SectionData
.Section
->FileObject
== NULL
)
120 return(STATUS_UNSUCCESSFUL
);
123 IoPageRead(MemoryArea
->Data
.SectionData
.Section
->FileObject
,
128 DPRINT("Returning from MmSectionHandleFault()\n");
130 return(STATUS_SUCCESS
);
133 asmlinkage
int page_fault_handler(unsigned int cs
,
136 * FUNCTION: Handle a page fault
139 KPROCESSOR_MODE FaultMode
;
140 MEMORY_AREA
* MemoryArea
;
145 * Get the address for the page fault
148 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
149 DPRINT("Page fault at address %x with eip %x\n",cr2
,eip
);
151 cr2
= PAGE_ROUND_DOWN(cr2
);
153 if (KeGetCurrentIrql()!=PASSIVE_LEVEL
)
155 DbgPrint("Recursive page fault detected\n");
160 KeRaiseIrql(DISPATCH_LEVEL
,&oldlvl
);
163 * Find the memory area for the faulting address
165 if (cr2
>=KERNEL_BASE
)
172 printk("%s:%d\n",__FILE__
,__LINE__
);
175 FaultMode
= UserMode
;
179 FaultMode
= KernelMode
;
182 MemoryArea
= MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID
)cr2
);
183 if (MemoryArea
==NULL
)
185 printk("%s:%d\n",__FILE__
,__LINE__
);
189 switch (MemoryArea
->Type
)
191 case MEMORY_AREA_SYSTEM
:
195 case MEMORY_AREA_SECTION_VIEW_COMMIT
:
196 if (MmSectionHandleFault(MemoryArea
, (PVOID
)cr2
)==STATUS_SUCCESS
)
206 case MEMORY_AREA_COMMIT
:
207 stat
= MmCommitedSectionHandleFault(MemoryArea
,cr2
);
221 BOOLEAN
MmIsNonPagedSystemAddressValid(PVOID VirtualAddress
)
226 BOOLEAN
MmIsAddressValid(PVOID VirtualAddress
)
228 * FUNCTION: Checks whether the given address is valid for a read or write
230 * VirtualAddress = address to check
231 * RETURNS: True if the access would be valid
232 * False if the access would cause a page fault
233 * NOTES: This function checks whether a byte access to the page would
234 * succeed. Is this realistic for RISC processors which don't
235 * allow byte granular access?
238 MEMORY_AREA
* MemoryArea
;
240 MemoryArea
= MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),
243 if (MemoryArea
== NULL
)
252 NtAllocateVirtualMemory(
253 IN HANDLE ProcessHandle
,
254 IN OUT PVOID
*BaseAddress
,
256 IN OUT PULONG RegionSize
,
257 IN ULONG AllocationType
,
261 return(ZwAllocateVirtualMemory(ProcessHandle
,
271 ZwAllocateVirtualMemory(
272 IN HANDLE ProcessHandle
,
273 IN OUT PVOID
*BaseAddress
,
275 IN OUT PULONG RegionSize
,
276 IN ULONG AllocationType
,
280 * FUNCTION: Allocates a block of virtual memory in the process address space
282 * ProcessHandle = The handle of the process which owns the virtual memory
283 * BaseAddress = A pointer to the virtual memory allocated. If you
284 * supply a non zero value the system will try to
285 * allocate the memory at the address supplied. It round
286 * it down to a multiple of the page size.
287 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
288 * that must be zero, ensuring that the memory will be
289 * allocated at a address below a certain value.
290 * RegionSize = The number of bytes to allocate
291 * AllocationType = Indicates the type of virtual memory you like to
292 * allocated, can be one of the values : MEM_COMMIT,
293 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
294 * Protect = Indicates the protection type of the pages allocated, can be
295 * a combination of PAGE_READONLY, PAGE_READWRITE,
296 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
299 * This function maps to the win32 VirtualAllocEx. Virtual memory is
300 * process based so the protocol starts with a ProcessHandle. I
301 * splitted the functionality of obtaining the actual address and
302 * specifying the start address in two parameters ( BaseAddress and
303 * StartAddress ) The NumberOfBytesAllocated specify the range and the
304 * AllocationType and ProctectionType map to the other two parameters.
309 MEMORY_AREA
* MemoryArea
;
313 DPRINT("ZwAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
314 "ZeroBits %d, RegionSize %d, AllocationType %x, Protect %x)\n",
315 ProcessHandle
,*BaseAddress
,ZeroBits
,*RegionSize
,AllocationType
,
318 Status
= ObReferenceObjectByHandle(ProcessHandle
,
319 PROCESS_VM_OPERATION
,
324 if (Status
!= STATUS_SUCCESS
)
326 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status
);
330 if (AllocationType
& MEM_RESERVE
)
332 Type
= MEMORY_AREA_RESERVE
;
336 Type
= MEMORY_AREA_COMMIT
;
339 if ((*BaseAddress
) != 0)
341 MemoryArea
= MmOpenMemoryAreaByAddress(Process
, *BaseAddress
);
343 if (MemoryArea
!= NULL
)
345 if (MemoryArea
->BaseAddress
== (*BaseAddress
) &&
346 MemoryArea
->Length
== *RegionSize
)
348 MemoryArea
->Type
= Type
;
349 MemoryArea
->Attributes
=Protect
;
350 DPRINT("*BaseAddress %x\n",*BaseAddress
);
351 return(STATUS_SUCCESS
);
354 MemoryArea
= MmSplitMemoryArea(Process
,
360 DPRINT("*BaseAddress %x\n",*BaseAddress
);
361 return(STATUS_SUCCESS
);
365 //FIXME RegionSize should be passed as pointer
368 Status
= MmCreateMemoryArea(UserMode
,
376 if (Status
!= STATUS_SUCCESS
)
378 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status
);
382 DPRINT("*BaseAddress %x\n",*BaseAddress
);
384 return(STATUS_SUCCESS
);
387 NTSTATUS STDCALL
NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
388 IN PVOID BaseAddress
,
389 IN ULONG NumberOfBytesToFlush
,
390 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
392 return(ZwFlushVirtualMemory(ProcessHandle
,
394 NumberOfBytesToFlush
,
395 NumberOfBytesFlushed
));
398 NTSTATUS STDCALL
ZwFlushVirtualMemory(IN HANDLE ProcessHandle
,
399 IN PVOID BaseAddress
,
400 IN ULONG NumberOfBytesToFlush
,
401 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
404 * FUNCTION: Flushes virtual memory to file
406 * ProcessHandle = Points to the process that allocated the virtual
408 * BaseAddress = Points to the memory address
409 * NumberOfBytesToFlush = Limits the range to flush,
410 * NumberOfBytesFlushed = Actual number of bytes flushed
417 NTSTATUS STDCALL
NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
418 IN PVOID
*BaseAddress
,
419 IN PULONG RegionSize
,
422 return(ZwFreeVirtualMemory(ProcessHandle
,
428 NTSTATUS STDCALL
ZwFreeVirtualMemory(IN HANDLE ProcessHandle
,
429 IN PVOID
*BaseAddress
,
430 IN PULONG RegionSize
,
434 * FUNCTION: Frees a range of virtual memory
436 * ProcessHandle = Points to the process that allocated the virtual
438 * BaseAddress = Points to the memory address, rounded down to a
439 * multiple of the pagesize
440 * RegionSize = Limits the range to free, rounded up to a multiple of
442 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
446 MEMORY_AREA
* MemoryArea
;
450 Status
= ObReferenceObjectByHandle(ProcessHandle
,
451 PROCESS_VM_OPERATION
,
456 if (Status
!= STATUS_SUCCESS
)
458 DbgPrint("ZwFreeVirtualMemory() = %x\n",Status
);
462 MemoryArea
= MmOpenMemoryAreaByAddress(Process
,*BaseAddress
);
463 if (MemoryArea
== NULL
)
465 return(STATUS_UNSUCCESSFUL
);
468 if (FreeType
== MEM_RELEASE
)
470 if (MemoryArea
->BaseAddress
!= (*BaseAddress
))
472 return(STATUS_UNSUCCESSFUL
);
474 MmFreeMemoryArea(PsGetCurrentProcess(),
478 return(STATUS_SUCCESS
);
484 NTSTATUS STDCALL
NtLockVirtualMemory(HANDLE ProcessHandle
,
486 ULONG NumberOfBytesToLock
,
487 PULONG NumberOfBytesLocked
)
489 return(ZwLockVirtualMemory(ProcessHandle
,
492 NumberOfBytesLocked
));
495 NTSTATUS STDCALL
ZwLockVirtualMemory(HANDLE ProcessHandle
,
497 ULONG NumberOfBytesToLock
,
498 PULONG NumberOfBytesLocked
)
503 NTSTATUS STDCALL
NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
504 IN PVOID BaseAddress
,
505 IN ULONG NumberOfBytesToProtect
,
506 IN ULONG NewAccessProtection
,
507 OUT PULONG OldAccessProtection
)
509 return(ZwProtectVirtualMemory(ProcessHandle
,
511 NumberOfBytesToProtect
,
513 OldAccessProtection
));
516 VOID
MmChangeAreaProtection(PEPROCESS Process
,
523 for (i
=0; i
<(Length
/PAGESIZE
); i
++)
525 if (MmIsPagePresent(Process
, BaseAddress
+ (i
*PAGESIZE
)))
527 MmSetPageProtect(Process
, BaseAddress
+ (i
*PAGESIZE
), Protect
);
532 NTSTATUS STDCALL
ZwProtectVirtualMemory(IN HANDLE ProcessHandle
,
533 IN PVOID BaseAddress
,
534 IN ULONG NumberOfBytesToProtect
,
535 IN ULONG NewAccessProtection
,
536 OUT PULONG OldAccessProtection
)
538 PMEMORY_AREA MemoryArea
;
542 Status
= ObReferenceObjectByHandle(ProcessHandle
,
543 PROCESS_VM_OPERATION
,
548 if (Status
!= STATUS_SUCCESS
)
550 DbgPrint("ZwProtectVirtualMemory() = %x\n",Status
);
554 MemoryArea
= MmOpenMemoryAreaByAddress(Process
,BaseAddress
);
555 if (MemoryArea
== NULL
)
557 DbgPrint("ZwProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL
);
558 return(STATUS_UNSUCCESSFUL
);
561 *OldAccessProtection
= MemoryArea
->Attributes
;
563 if (MemoryArea
->BaseAddress
== BaseAddress
&&
564 MemoryArea
->Length
== NumberOfBytesToProtect
)
566 MemoryArea
->Attributes
= NewAccessProtection
;
570 MemoryArea
= MmSplitMemoryArea(Process
,
573 NumberOfBytesToProtect
,
575 NewAccessProtection
);
577 MmChangeAreaProtection(Process
,BaseAddress
,NumberOfBytesToProtect
,
578 NewAccessProtection
);
579 return(STATUS_SUCCESS
);
583 NTSTATUS STDCALL
NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
585 IN IN CINT VirtualMemoryInformationClass
,
586 OUT PVOID VirtualMemoryInformation
,
588 OUT PULONG ResultLength
)
590 return(ZwQueryVirtualMemory(ProcessHandle
,
592 VirtualMemoryInformationClass
,
593 VirtualMemoryInformation
,
598 NTSTATUS STDCALL
ZwQueryVirtualMemory(IN HANDLE ProcessHandle
,
600 IN CINT VirtualMemoryInformationClass
,
601 OUT PVOID VirtualMemoryInformation
,
603 OUT PULONG ResultLength
)
608 NTSTATUS STDCALL
NtReadVirtualMemory(IN HANDLE ProcessHandle
,
609 IN PVOID BaseAddress
,
611 IN ULONG NumberOfBytesToRead
,
612 OUT PULONG NumberOfBytesRead
)
614 return(ZwReadVirtualMemory(ProcessHandle
,
621 NTSTATUS STDCALL
ZwReadVirtualMemory(IN HANDLE ProcessHandle
,
622 IN PVOID BaseAddress
,
624 IN ULONG NumberOfBytesToRead
,
625 OUT PULONG NumberOfBytesRead
)
628 MEMORY_AREA
* MemoryArea
;
633 Status
= ObReferenceObjectByHandle(ProcessHandle
,
639 if (Status
!= STATUS_SUCCESS
)
644 MemoryArea
= MmOpenMemoryAreaByAddress(Process
,BaseAddress
);
646 if (MemoryArea
== NULL
)
648 return(STATUS_UNSUCCESSFUL
);
650 if (MemoryArea
->Length
> NumberOfBytesToRead
)
652 NumberOfBytesToRead
= MemoryArea
->Length
;
655 *NumberOfBytesRead
= NumberOfBytesToRead
;
657 for (i
=0; i
<(NumberOfBytesToRead
/PAGESIZE
); i
++)
659 CurrentEntry
= MmGetPageEntry(Process
, (DWORD
)BaseAddress
+ (i
*PAGESIZE
));
660 RtlCopyMemory(Buffer
+ (i
*PAGESIZE
),
661 (PVOID
)physical_to_linear(PAGE_MASK(*CurrentEntry
)),
665 return(STATUS_SUCCESS
);
668 NTSTATUS STDCALL
NtUnlockVirtualMemory(HANDLE ProcessHandle
,
670 ULONG NumberOfBytesToUnlock
,
671 PULONG NumberOfBytesUnlocked OPTIONAL
)
673 return(ZwUnlockVirtualMemory(ProcessHandle
,
675 NumberOfBytesToUnlock
,
676 NumberOfBytesUnlocked
));
679 NTSTATUS STDCALL
ZwUnlockVirtualMemory(HANDLE ProcessHandle
,
681 ULONG NumberOfBytesToUnlock
,
682 PULONG NumberOfBytesUnlocked OPTIONAL
)
687 NTSTATUS STDCALL
NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
688 IN PVOID BaseAddress
,
690 IN ULONG NumberOfBytesToWrite
,
691 OUT PULONG NumberOfBytesWritten
)
693 return(ZwWriteVirtualMemory(ProcessHandle
,
696 NumberOfBytesToWrite
,
697 NumberOfBytesWritten
));
700 NTSTATUS STDCALL
ZwWriteVirtualMemory(IN HANDLE ProcessHandle
,
701 IN PVOID BaseAddress
,
703 IN ULONG NumberOfBytesToWrite
,
704 OUT PULONG NumberOfBytesWritten
)
707 MEMORY_AREA
* MemoryArea
;
712 Status
= ObReferenceObjectByHandle(ProcessHandle
,
718 if (Status
!= STATUS_SUCCESS
)
723 MemoryArea
= MmOpenMemoryAreaByAddress(Process
,BaseAddress
);
725 if (MemoryArea
== NULL
)
727 return(STATUS_UNSUCCESSFUL
);
729 if (MemoryArea
->Length
> NumberOfBytesToWrite
)
731 NumberOfBytesToWrite
= MemoryArea
->Length
;
734 *NumberOfBytesWritten
= NumberOfBytesToWrite
;
736 for (i
=0; i
<(NumberOfBytesToWrite
/PAGESIZE
); i
++)
738 CurrentEntry
= MmGetPageEntry(Process
, (DWORD
)BaseAddress
+ (i
*PAGESIZE
));
739 RtlCopyMemory((PVOID
)physical_to_linear(PAGE_MASK(*CurrentEntry
)),
740 Buffer
+ (i
*PAGESIZE
),
744 return(STATUS_SUCCESS
);