no message
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
1 /*
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
7 * UPDATE HISTORY:
8 * 09/4/98: Created
9 * 10/6/98: Corrections from Fatahi (i_fatahi@hotmail.com)
10 * 30/9/98: Implemented ZwxxxVirtualMemory functions
11 */
12
13 /* INCLUDE *****************************************************************/
14
15 #include <windows.h>
16
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>
23
24 #define NDEBUG
25 #include <internal/debug.h>
26
27 /* TYPES *******************************************************************/
28
29 extern unsigned int etext;
30 extern unsigned int end;
31
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;
36
37 /* FUNCTIONS ****************************************************************/
38
39 void VirtualInit(boot_param* bp)
40 /*
41 * FUNCTION: Intialize the memory areas list
42 * ARGUMENTS:
43 * bp = Pointer to the boot parameters
44 * kernel_len = Length of the kernel
45 */
46 {
47 unsigned int kernel_len = bp->end_mem - bp->start_mem;
48 PVOID BaseAddress;
49 ULONG Length;
50 ULONG ParamLength = kernel_len;
51
52 DPRINT("VirtualInit() %x\n",bp);
53
54 MmInitMemoryAreas();
55 ExInitNonPagedPool(KERNEL_BASE+ PAGE_ROUND_UP(kernel_len) + PAGESIZE);
56
57
58 /*
59 * Setup the system area descriptor list
60 */
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);
66
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,
72 NULL,
73 MEMORY_AREA_SYSTEM,
74 &BaseAddress,
75 Length,
76 0,
77 &kernel_data_desc);
78
79
80 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&end));
81 Length = ParamLength;
82 MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
83 Length,0,&kernel_param_desc);
84
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);
89
90 // MmDumpMemoryAreas();
91 CHECKPOINT;
92
93 MmInitSectionImplementation();
94 }
95
96 ULONG MmCommitedSectionHandleFault(MEMORY_AREA* MemoryArea, ULONG Address)
97 {
98 MmSetPage(PsGetCurrentProcess(),
99 Address,
100 MemoryArea->Attributes,
101 get_free_page());
102 return(TRUE);
103 }
104
105 NTSTATUS MmSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
106 {
107 LARGE_INTEGER Offset;
108 IO_STATUS_BLOCK IoStatus;
109
110 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
111 MemoryArea,Address);
112
113 MmSetPage(NULL,
114 Address,
115 MemoryArea->Attributes,
116 get_free_page());
117
118 LARGE_INTEGER_QUAD_PART(Offset) = (Address - MemoryArea->BaseAddress) +
119 MemoryArea->Data.SectionData.ViewOffset;
120
121 DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
122 MemoryArea->Data.SectionData.Section->FileObject);
123
124 if (MemoryArea->Data.SectionData.Section->FileObject == NULL)
125 {
126 return(STATUS_UNSUCCESSFUL);
127 }
128
129 IoPageRead(MemoryArea->Data.SectionData.Section->FileObject,
130 (PVOID)Address,
131 &Offset,
132 &IoStatus);
133
134 DPRINT("Returning from MmSectionHandleFault()\n");
135
136 return(STATUS_SUCCESS);
137 }
138
139 asmlinkage int page_fault_handler(unsigned int cs,
140 unsigned int eip)
141 /*
142 * FUNCTION: Handle a page fault
143 */
144 {
145 KPROCESSOR_MODE FaultMode;
146 MEMORY_AREA* MemoryArea;
147 KIRQL oldlvl;
148 ULONG stat;
149
150 /*
151 * Get the address for the page fault
152 */
153 unsigned int cr2;
154 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
155 DPRINT("Page fault at address %x with eip %x\n",cr2,eip);
156
157 cr2 = PAGE_ROUND_DOWN(cr2);
158
159 if (KeGetCurrentIrql()!=PASSIVE_LEVEL)
160 {
161 DbgPrint("Page fault at high IRQL\n");
162 return(0);
163 // KeBugCheck(0);
164 }
165
166 KeRaiseIrql(DISPATCH_LEVEL,&oldlvl);
167
168 /*
169 * Find the memory area for the faulting address
170 */
171 if (cr2>=KERNEL_BASE)
172 {
173 /*
174 * Check permissions
175 */
176 if (cs!=KERNEL_CS)
177 {
178 printk("%s:%d\n",__FILE__,__LINE__);
179 return(0);
180 }
181 FaultMode = UserMode;
182 }
183 else
184 {
185 FaultMode = KernelMode;
186 }
187
188 MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID)cr2);
189 if (MemoryArea==NULL)
190 {
191 printk("%s:%d\n",__FILE__,__LINE__);
192 return(0);
193 }
194
195 switch (MemoryArea->Type)
196 {
197 case MEMORY_AREA_SYSTEM:
198 stat = 0;
199 break;
200
201 case MEMORY_AREA_SECTION_VIEW_COMMIT:
202 if (MmSectionHandleFault(MemoryArea, (PVOID)cr2)==STATUS_SUCCESS)
203 {
204 stat=1;
205 }
206 else
207 {
208 stat = 0;
209 }
210 break;
211
212 case MEMORY_AREA_COMMIT:
213 stat = MmCommitedSectionHandleFault(MemoryArea,cr2);
214 break;
215
216 default:
217 stat = 0;
218 break;
219 }
220 if (stat)
221 {
222 KeLowerIrql(oldlvl);
223 }
224 return(stat);
225 }
226
227 BOOLEAN MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
228 {
229 UNIMPLEMENTED;
230 }
231
232 BOOLEAN MmIsAddressValid(PVOID VirtualAddress)
233 /*
234 * FUNCTION: Checks whether the given address is valid for a read or write
235 * ARGUMENTS:
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?
242 */
243 {
244 MEMORY_AREA* MemoryArea;
245
246 MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),
247 VirtualAddress);
248
249 if (MemoryArea == NULL)
250 {
251 return(FALSE);
252 }
253 return(TRUE);
254 }
255
256 NTSTATUS
257 STDCALL
258 NtAllocateVirtualMemory(
259 IN HANDLE ProcessHandle,
260 IN OUT PVOID *BaseAddress,
261 IN ULONG ZeroBits,
262 IN OUT PULONG RegionSize,
263 IN ULONG AllocationType,
264 IN ULONG Protect
265 )
266 {
267 return(ZwAllocateVirtualMemory(ProcessHandle,
268 BaseAddress,
269 ZeroBits,
270 RegionSize,
271 AllocationType,
272 Protect));
273 }
274
275 NTSTATUS
276 STDCALL
277 ZwAllocateVirtualMemory(
278 IN HANDLE ProcessHandle,
279 IN OUT PVOID *BaseAddress,
280 IN ULONG ZeroBits,
281 IN OUT PULONG RegionSize,
282 IN ULONG AllocationType,
283 IN ULONG Protect
284 )
285 /*
286 * FUNCTION: Allocates a block of virtual memory in the process address space
287 * ARGUMENTS:
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,
303 * PAGE_NOACCESS
304 * REMARKS:
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.
311 * RETURNS: Status
312 */
313 {
314 PEPROCESS Process;
315 MEMORY_AREA* MemoryArea;
316 ULONG Type;
317 NTSTATUS Status;
318
319 DPRINT("ZwAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
320 "ZeroBits %d, RegionSize %d, AllocationType %x, Protect %x)\n",
321 ProcessHandle,*BaseAddress,ZeroBits,*RegionSize,AllocationType,
322 Protect);
323
324 Status = ObReferenceObjectByHandle(ProcessHandle,
325 PROCESS_VM_OPERATION,
326 NULL,
327 UserMode,
328 (PVOID*)(&Process),
329 NULL);
330 if (Status != STATUS_SUCCESS)
331 {
332 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status);
333 return(Status);
334 }
335
336 if (AllocationType & MEM_RESERVE)
337 {
338 Type = MEMORY_AREA_RESERVE;
339 }
340 else
341 {
342 Type = MEMORY_AREA_COMMIT;
343 }
344
345 if ((*BaseAddress) != 0)
346 {
347 MemoryArea = MmOpenMemoryAreaByAddress(Process, *BaseAddress);
348
349 if (MemoryArea != NULL)
350 {
351 if (MemoryArea->BaseAddress == (*BaseAddress) &&
352 MemoryArea->Length == *RegionSize)
353 {
354 MemoryArea->Type = Type;
355 MemoryArea->Attributes =Protect;
356 DPRINT("*BaseAddress %x\n",*BaseAddress);
357 return(STATUS_SUCCESS);
358 }
359
360 MemoryArea = MmSplitMemoryArea(Process,
361 MemoryArea,
362 *BaseAddress,
363 *RegionSize,
364 Type,
365 Protect);
366 DPRINT("*BaseAddress %x\n",*BaseAddress);
367 return(STATUS_SUCCESS);
368 }
369 }
370
371 //FIXME RegionSize should be passed as pointer
372
373
374 Status = MmCreateMemoryArea(UserMode,
375 Process,
376 Type,
377 BaseAddress,
378 *RegionSize,
379 Protect,
380 &MemoryArea);
381
382 if (Status != STATUS_SUCCESS)
383 {
384 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status);
385 return(Status);
386 }
387
388 DPRINT("*BaseAddress %x\n",*BaseAddress);
389
390 return(STATUS_SUCCESS);
391 }
392
393 NTSTATUS STDCALL NtFlushVirtualMemory(IN HANDLE ProcessHandle,
394 IN PVOID BaseAddress,
395 IN ULONG NumberOfBytesToFlush,
396 OUT PULONG NumberOfBytesFlushed OPTIONAL)
397 {
398 return(ZwFlushVirtualMemory(ProcessHandle,
399 BaseAddress,
400 NumberOfBytesToFlush,
401 NumberOfBytesFlushed));
402 }
403
404 NTSTATUS STDCALL ZwFlushVirtualMemory(IN HANDLE ProcessHandle,
405 IN PVOID BaseAddress,
406 IN ULONG NumberOfBytesToFlush,
407 OUT PULONG NumberOfBytesFlushed OPTIONAL)
408
409 /*
410 * FUNCTION: Flushes virtual memory to file
411 * ARGUMENTS:
412 * ProcessHandle = Points to the process that allocated the virtual
413 * memory
414 * BaseAddress = Points to the memory address
415 * NumberOfBytesToFlush = Limits the range to flush,
416 * NumberOfBytesFlushed = Actual number of bytes flushed
417 * RETURNS: Status
418 */
419 {
420 UNIMPLEMENTED;
421 }
422
423 NTSTATUS STDCALL NtFreeVirtualMemory(IN HANDLE ProcessHandle,
424 IN PVOID *BaseAddress,
425 IN PULONG RegionSize,
426 IN ULONG FreeType)
427 {
428 return(ZwFreeVirtualMemory(ProcessHandle,
429 BaseAddress,
430 RegionSize,
431 FreeType));
432 }
433
434 NTSTATUS STDCALL ZwFreeVirtualMemory(IN HANDLE ProcessHandle,
435 IN PVOID *BaseAddress,
436 IN PULONG RegionSize,
437 IN ULONG FreeType)
438
439 /*
440 * FUNCTION: Frees a range of virtual memory
441 * ARGUMENTS:
442 * ProcessHandle = Points to the process that allocated the virtual
443 * memory
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
447 * the paging size
448 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
449 * RETURNS: Status
450 */
451 {
452 MEMORY_AREA* MemoryArea;
453 NTSTATUS Status;
454 PEPROCESS Process;
455
456 Status = ObReferenceObjectByHandle(ProcessHandle,
457 PROCESS_VM_OPERATION,
458 PsProcessType,
459 UserMode,
460 (PVOID*)(&Process),
461 NULL);
462 if (Status != STATUS_SUCCESS)
463 {
464 return(Status);
465 }
466
467 MemoryArea = MmOpenMemoryAreaByAddress(Process,*BaseAddress);
468 if (MemoryArea == NULL)
469 {
470 return(STATUS_UNSUCCESSFUL);
471 }
472
473 switch (FreeType)
474 {
475 case MEM_RELEASE:
476 if (MemoryArea->BaseAddress != (*BaseAddress))
477 {
478 return(STATUS_UNSUCCESSFUL);
479 }
480 MmFreeMemoryArea(PsGetCurrentProcess(),
481 BaseAddress,
482 0,
483 TRUE);
484 return(STATUS_SUCCESS);
485
486 case MEM_DECOMMIT:
487 MmSplitMemoryArea(PsGetCurrentProcess(),
488 MemoryArea,
489 *BaseAddress,
490 *RegionSize,
491 MEMORY_AREA_RESERVE,
492 MemoryArea->Attributes);
493 return(STATUS_SUCCESS);
494 }
495
496 return(STATUS_NOT_IMPLEMENTED);
497 }
498
499 NTSTATUS STDCALL NtLockVirtualMemory(HANDLE ProcessHandle,
500 PVOID BaseAddress,
501 ULONG NumberOfBytesToLock,
502 PULONG NumberOfBytesLocked)
503 {
504 return(ZwLockVirtualMemory(ProcessHandle,
505 BaseAddress,
506 NumberOfBytesToLock,
507 NumberOfBytesLocked));
508 }
509
510 NTSTATUS STDCALL ZwLockVirtualMemory(HANDLE ProcessHandle,
511 PVOID BaseAddress,
512 ULONG NumberOfBytesToLock,
513 PULONG NumberOfBytesLocked)
514 {
515 UNIMPLEMENTED;
516 }
517
518 NTSTATUS STDCALL NtProtectVirtualMemory(IN HANDLE ProcessHandle,
519 IN PVOID BaseAddress,
520 IN ULONG NumberOfBytesToProtect,
521 IN ULONG NewAccessProtection,
522 OUT PULONG OldAccessProtection)
523 {
524 return(ZwProtectVirtualMemory(ProcessHandle,
525 BaseAddress,
526 NumberOfBytesToProtect,
527 NewAccessProtection,
528 OldAccessProtection));
529 }
530
531 VOID MmChangeAreaProtection(PEPROCESS Process,
532 PVOID BaseAddress,
533 ULONG Length,
534 ULONG Protect)
535 {
536 ULONG i;
537
538 for (i=0; i<(Length/PAGESIZE); i++)
539 {
540 if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
541 {
542 MmSetPageProtect(Process, BaseAddress + (i*PAGESIZE), Protect);
543 }
544 }
545 }
546
547 NTSTATUS STDCALL ZwProtectVirtualMemory(IN HANDLE ProcessHandle,
548 IN PVOID BaseAddress,
549 IN ULONG NumberOfBytesToProtect,
550 IN ULONG NewAccessProtection,
551 OUT PULONG OldAccessProtection)
552 {
553 PMEMORY_AREA MemoryArea;
554 PEPROCESS Process;
555 NTSTATUS Status;
556
557 Status = ObReferenceObjectByHandle(ProcessHandle,
558 PROCESS_VM_OPERATION,
559 PsProcessType,
560 UserMode,
561 (PVOID*)(&Process),
562 NULL);
563 if (Status != STATUS_SUCCESS)
564 {
565 DbgPrint("ZwProtectVirtualMemory() = %x\n",Status);
566 return(Status);
567 }
568
569 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
570 if (MemoryArea == NULL)
571 {
572 DbgPrint("ZwProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
573 return(STATUS_UNSUCCESSFUL);
574 }
575
576 *OldAccessProtection = MemoryArea->Attributes;
577
578 if (MemoryArea->BaseAddress == BaseAddress &&
579 MemoryArea->Length == NumberOfBytesToProtect)
580 {
581 MemoryArea->Attributes = NewAccessProtection;
582 }
583 else
584 {
585 MemoryArea = MmSplitMemoryArea(Process,
586 MemoryArea,
587 BaseAddress,
588 NumberOfBytesToProtect,
589 MemoryArea->Type,
590 NewAccessProtection);
591 }
592 MmChangeAreaProtection(Process,BaseAddress,NumberOfBytesToProtect,
593 NewAccessProtection);
594 return(STATUS_SUCCESS);
595 }
596
597
598 NTSTATUS STDCALL NtQueryVirtualMemory(IN HANDLE ProcessHandle,
599 IN PVOID Address,
600 IN IN CINT VirtualMemoryInformationClass,
601 OUT PVOID VirtualMemoryInformation,
602 IN ULONG Length,
603 OUT PULONG ResultLength)
604 {
605 return(ZwQueryVirtualMemory(ProcessHandle,
606 Address,
607 VirtualMemoryInformationClass,
608 VirtualMemoryInformation,
609 Length,
610 ResultLength));
611 }
612
613 NTSTATUS STDCALL ZwQueryVirtualMemory(IN HANDLE ProcessHandle,
614 IN PVOID Address,
615 IN CINT VirtualMemoryInformationClass,
616 OUT PVOID VirtualMemoryInformation,
617 IN ULONG Length,
618 OUT PULONG ResultLength)
619 {
620 UNIMPLEMENTED;
621 }
622
623 NTSTATUS STDCALL NtReadVirtualMemory(IN HANDLE ProcessHandle,
624 IN PVOID BaseAddress,
625 OUT PVOID Buffer,
626 IN ULONG NumberOfBytesToRead,
627 OUT PULONG NumberOfBytesRead)
628 {
629 return(ZwReadVirtualMemory(ProcessHandle,
630 BaseAddress,
631 Buffer,
632 NumberOfBytesToRead,
633 NumberOfBytesRead));
634 }
635
636 NTSTATUS STDCALL ZwReadVirtualMemory(IN HANDLE ProcessHandle,
637 IN PVOID BaseAddress,
638 OUT PVOID Buffer,
639 IN ULONG NumberOfBytesToRead,
640 OUT PULONG NumberOfBytesRead)
641 {
642 PEPROCESS Process;
643 MEMORY_AREA* MemoryArea;
644 ULONG i;
645 NTSTATUS Status;
646 PULONG CurrentEntry;
647
648 Status = ObReferenceObjectByHandle(ProcessHandle,
649 PROCESS_VM_READ,
650 NULL,
651 UserMode,
652 (PVOID*)(&Process),
653 NULL);
654 if (Status != STATUS_SUCCESS)
655 {
656 return(Status);
657 }
658
659 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
660
661 if (MemoryArea == NULL)
662 {
663 return(STATUS_UNSUCCESSFUL);
664 }
665 if (MemoryArea->Length > NumberOfBytesToRead)
666 {
667 NumberOfBytesToRead = MemoryArea->Length;
668 }
669
670 *NumberOfBytesRead = NumberOfBytesToRead;
671
672 for (i=0; i<(NumberOfBytesToRead/PAGESIZE); i++)
673 {
674 CurrentEntry = MmGetPageEntry(Process, (DWORD)BaseAddress + (i*PAGESIZE));
675 RtlCopyMemory(Buffer + (i*PAGESIZE),
676 (PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)),
677 PAGESIZE);
678
679 }
680 return(STATUS_SUCCESS);
681 }
682
683 NTSTATUS STDCALL NtUnlockVirtualMemory(HANDLE ProcessHandle,
684 PVOID BaseAddress,
685 ULONG NumberOfBytesToUnlock,
686 PULONG NumberOfBytesUnlocked OPTIONAL)
687 {
688 return(ZwUnlockVirtualMemory(ProcessHandle,
689 BaseAddress,
690 NumberOfBytesToUnlock,
691 NumberOfBytesUnlocked));
692 }
693
694 NTSTATUS STDCALL ZwUnlockVirtualMemory(HANDLE ProcessHandle,
695 PVOID BaseAddress,
696 ULONG NumberOfBytesToUnlock,
697 PULONG NumberOfBytesUnlocked OPTIONAL)
698 {
699 UNIMPLEMENTED;
700 }
701
702 NTSTATUS STDCALL NtWriteVirtualMemory(IN HANDLE ProcessHandle,
703 IN PVOID BaseAddress,
704 IN PVOID Buffer,
705 IN ULONG NumberOfBytesToWrite,
706 OUT PULONG NumberOfBytesWritten)
707 {
708 return(ZwWriteVirtualMemory(ProcessHandle,
709 BaseAddress,
710 Buffer,
711 NumberOfBytesToWrite,
712 NumberOfBytesWritten));
713 }
714
715 NTSTATUS STDCALL ZwWriteVirtualMemory(IN HANDLE ProcessHandle,
716 IN PVOID BaseAddress,
717 IN PVOID Buffer,
718 IN ULONG NumberOfBytesToWrite,
719 OUT PULONG NumberOfBytesWritten)
720 {
721 PEPROCESS Process;
722 PMEMORY_AREA InMemoryArea;
723 PMEMORY_AREA OutMemoryArea;
724 ULONG i;
725 NTSTATUS Status;
726 PULONG CurrentEntry;
727
728 DPRINT("ZwWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
729 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
730 Buffer,NumberOfBytesToWrite);
731
732 Status = ObReferenceObjectByHandle(ProcessHandle,
733 PROCESS_VM_WRITE,
734 NULL,
735 UserMode,
736 (PVOID*)(&Process),
737 NULL);
738 if (Status != STATUS_SUCCESS)
739 {
740 return(Status);
741 }
742
743 OutMemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
744 if (OutMemoryArea == NULL)
745 {
746 return(STATUS_UNSUCCESSFUL);
747 }
748
749 *NumberOfBytesWritten = NumberOfBytesToWrite;
750
751 DPRINT("*Buffer %x\n",((PULONG)Buffer)[0]);
752
753 for (i=0; i<(PAGE_ROUND_DOWN(NumberOfBytesToWrite)/PAGESIZE); i++)
754 {
755 if (!MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
756 {
757 DPRINT("OutMemoryArea->Attributes %x\n",
758 OutMemoryArea->Attributes);
759 MmSetPage(Process,
760 BaseAddress + (i*PAGESIZE),
761 OutMemoryArea->Attributes,
762 get_free_page());
763 }
764 CurrentEntry = MmGetPageEntry(Process, (DWORD)BaseAddress +
765 (i*PAGESIZE));
766 RtlCopyMemory((PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)) +
767 (((DWORD)BaseAddress)%PAGESIZE),
768 Buffer + (i*PAGESIZE),
769 PAGESIZE);
770 }
771 if ((NumberOfBytesToWrite % PAGESIZE) != 0)
772 {
773 if (!MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
774 {
775 MmSetPage(Process,
776 BaseAddress + (i*PAGESIZE),
777 OutMemoryArea->Attributes,
778 get_free_page());
779 }
780 CurrentEntry = MmGetPageEntry(Process,
781 BaseAddress + (i*PAGESIZE));
782 DPRINT("addr %x\n",
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);
789 }
790 return(STATUS_SUCCESS);
791 }
792
793