Corrected a memory leak in the read cleanup code
[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 set_page(Address,0x7,get_free_page());
99 return(TRUE);
100 }
101
102 NTSTATUS MmSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
103 {
104 LARGE_INTEGER Offset;
105 IO_STATUS_BLOCK IoStatus;
106
107 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
108 MemoryArea,Address);
109
110 set_page(Address,0x7,get_free_page());
111
112 Offset.LowPart = (Address - MemoryArea->BaseAddress) +
113 MemoryArea->Data.SectionData.ViewOffset;
114
115 DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
116 MemoryArea->Data.SectionData.Section->FileObject);
117
118 if (MemoryArea->Data.SectionData.Section->FileObject == NULL)
119 {
120 return(STATUS_UNSUCCESSFUL);
121 }
122
123 IoPageRead(MemoryArea->Data.SectionData.Section->FileObject,
124 (PVOID)Address,
125 &Offset,
126 &IoStatus);
127
128 DPRINT("Returning from MmSectionHandleFault()\n");
129
130 return(STATUS_SUCCESS);
131 }
132
133 asmlinkage int page_fault_handler(unsigned int cs,
134 unsigned int eip)
135 /*
136 * FUNCTION: Handle a page fault
137 */
138 {
139 KPROCESSOR_MODE FaultMode;
140 MEMORY_AREA* MemoryArea;
141 KIRQL oldlvl;
142 ULONG stat;
143
144 /*
145 * Get the address for the page fault
146 */
147 unsigned int cr2;
148 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
149 DPRINT("Page fault at address %x with eip %x\n",cr2,eip);
150
151 cr2 = PAGE_ROUND_DOWN(cr2);
152
153 if (KeGetCurrentIrql()!=PASSIVE_LEVEL)
154 {
155 DbgPrint("Recursive page fault detected\n");
156 return(0);
157 // KeBugCheck(0);
158 }
159
160 KeRaiseIrql(DISPATCH_LEVEL,&oldlvl);
161
162 /*
163 * Find the memory area for the faulting address
164 */
165 if (cr2>=KERNEL_BASE)
166 {
167 /*
168 * Check permissions
169 */
170 if (cs!=KERNEL_CS)
171 {
172 printk("%s:%d\n",__FILE__,__LINE__);
173 return(0);
174 }
175 FaultMode = UserMode;
176 }
177 else
178 {
179 FaultMode = KernelMode;
180 }
181
182 MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID)cr2);
183 if (MemoryArea==NULL)
184 {
185 printk("%s:%d\n",__FILE__,__LINE__);
186 return(0);
187 }
188
189 switch (MemoryArea->Type)
190 {
191 case MEMORY_AREA_SYSTEM:
192 stat = 0;
193 break;
194
195 case MEMORY_AREA_SECTION_VIEW_COMMIT:
196 if (MmSectionHandleFault(MemoryArea,cr2)==STATUS_SUCCESS)
197 {
198 stat=1;
199 }
200 else
201 {
202 stat = 0;
203 }
204 break;
205
206 case MEMORY_AREA_COMMIT:
207 stat = MmCommitedSectionHandleFault(MemoryArea,cr2);
208 break;
209
210 default:
211 stat = 0;
212 break;
213 }
214 if (stat)
215 {
216 KeLowerIrql(oldlvl);
217 }
218 return(stat);
219 }
220
221 BOOLEAN MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
222 {
223 UNIMPLEMENTED;
224 }
225
226 BOOLEAN MmIsAddressValid(PVOID VirtualAddress)
227 /*
228 * FUNCTION: Checks whether the given address is valid for a read or write
229 * ARGUMENTS:
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?
236 */
237 {
238 MEMORY_AREA* MemoryArea;
239
240 MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),
241 VirtualAddress);
242
243 if (MemoryArea == NULL)
244 {
245 return(FALSE);
246 }
247 return(TRUE);
248 }
249
250 NTSTATUS
251 STDCALL
252 NtAllocateVirtualMemory(
253 IN HANDLE ProcessHandle,
254 IN OUT PVOID *BaseAddress,
255 IN ULONG ZeroBits,
256 IN OUT PULONG RegionSize,
257 IN ULONG AllocationType,
258 IN ULONG Protect
259 )
260 {
261 return(ZwAllocateVirtualMemory(ProcessHandle,
262 BaseAddress,
263 ZeroBits,
264 RegionSize,
265 AllocationType,
266 Protect));
267 }
268
269 NTSTATUS
270 STDCALL
271 ZwAllocateVirtualMemory(
272 IN HANDLE ProcessHandle,
273 IN OUT PVOID *BaseAddress,
274 IN ULONG ZeroBits,
275 IN OUT PULONG RegionSize,
276 IN ULONG AllocationType,
277 IN ULONG Protect
278 )
279 /*
280 * FUNCTION: Allocates a block of virtual memory in the process address space
281 * ARGUMENTS:
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,
297 * PAGE_NOACCESS
298 * REMARKS:
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.
305 * RETURNS: Status
306 */
307 {
308 PEPROCESS Process;
309 MEMORY_AREA* MemoryArea;
310 ULONG Type;
311 NTSTATUS Status;
312
313 DPRINT("ZwAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
314 "ZeroBits %d, RegionSize %d, AllocationType %x, Protect %x)\n",
315 ProcessHandle,*BaseAddress,ZeroBits,*RegionSize,AllocationType,
316 Protect);
317
318 Status = ObReferenceObjectByHandle(ProcessHandle,
319 PROCESS_VM_OPERATION,
320 NULL,
321 UserMode,
322 (PVOID*)(&Process),
323 NULL);
324 if (Status != STATUS_SUCCESS)
325 {
326 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status);
327 return(Status);
328 }
329
330 if (AllocationType & MEM_RESERVE)
331 {
332 Type = MEMORY_AREA_RESERVE;
333 }
334 else
335 {
336 Type = MEMORY_AREA_COMMIT;
337 }
338
339 if ((*BaseAddress) != 0)
340 {
341 MemoryArea = MmOpenMemoryAreaByAddress(Process, *BaseAddress);
342
343 if (MemoryArea != NULL)
344 {
345 if (MemoryArea->BaseAddress == (*BaseAddress) &&
346 MemoryArea->Length == *RegionSize)
347 {
348 MemoryArea->Type = Type;
349 MemoryArea->Attributes =Protect;
350 DPRINT("*BaseAddress %x\n",*BaseAddress);
351 return(STATUS_SUCCESS);
352 }
353
354 MemoryArea = MmSplitMemoryArea(Process,
355 MemoryArea,
356 *BaseAddress,
357 *RegionSize,
358 Type,
359 Protect);
360 DPRINT("*BaseAddress %x\n",*BaseAddress);
361 return(STATUS_SUCCESS);
362 }
363 }
364
365 //FIXME RegionSize should be passed as pointer
366
367
368 Status = MmCreateMemoryArea(UserMode,
369 Process,
370 Type,
371 BaseAddress,
372 *RegionSize,
373 Protect,
374 &MemoryArea);
375
376 if (Status != STATUS_SUCCESS)
377 {
378 DPRINT("ZwAllocateVirtualMemory() = %x\n",Status);
379 return(Status);
380 }
381
382 DPRINT("*BaseAddress %x\n",*BaseAddress);
383
384 return(STATUS_SUCCESS);
385 }
386
387 NTSTATUS STDCALL NtFlushVirtualMemory(IN HANDLE ProcessHandle,
388 IN PVOID BaseAddress,
389 IN ULONG NumberOfBytesToFlush,
390 OUT PULONG NumberOfBytesFlushed OPTIONAL)
391 {
392 return(ZwFlushVirtualMemory(ProcessHandle,
393 BaseAddress,
394 NumberOfBytesToFlush,
395 NumberOfBytesFlushed));
396 }
397
398 NTSTATUS STDCALL ZwFlushVirtualMemory(IN HANDLE ProcessHandle,
399 IN PVOID BaseAddress,
400 IN ULONG NumberOfBytesToFlush,
401 OUT PULONG NumberOfBytesFlushed OPTIONAL)
402
403 /*
404 * FUNCTION: Flushes virtual memory to file
405 * ARGUMENTS:
406 * ProcessHandle = Points to the process that allocated the virtual
407 * memory
408 * BaseAddress = Points to the memory address
409 * NumberOfBytesToFlush = Limits the range to flush,
410 * NumberOfBytesFlushed = Actual number of bytes flushed
411 * RETURNS: Status
412 */
413 {
414 UNIMPLEMENTED;
415 }
416
417 NTSTATUS STDCALL NtFreeVirtualMemory(IN HANDLE ProcessHandle,
418 IN PVOID *BaseAddress,
419 IN PULONG RegionSize,
420 IN ULONG FreeType)
421 {
422 return(ZwFreeVirtualMemory(ProcessHandle,
423 BaseAddress,
424 RegionSize,
425 FreeType));
426 }
427
428 NTSTATUS STDCALL ZwFreeVirtualMemory(IN HANDLE ProcessHandle,
429 IN PVOID *BaseAddress,
430 IN PULONG RegionSize,
431 IN ULONG FreeType)
432
433 /*
434 * FUNCTION: Frees a range of virtual memory
435 * ARGUMENTS:
436 * ProcessHandle = Points to the process that allocated the virtual
437 * memory
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
441 * the paging size
442 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
443 * RETURNS: Status
444 */
445 {
446 MEMORY_AREA* MemoryArea;
447 NTSTATUS Status;
448 PEPROCESS Process;
449
450 Status = ObReferenceObjectByHandle(ProcessHandle,
451 PROCESS_VM_OPERATION,
452 PsProcessType,
453 UserMode,
454 (PVOID*)(&Process),
455 NULL);
456 if (Status != STATUS_SUCCESS)
457 {
458 DbgPrint("ZwFreeVirtualMemory() = %x\n",Status);
459 return(Status);
460 }
461
462 MemoryArea = MmOpenMemoryAreaByAddress(Process,*BaseAddress);
463 if (MemoryArea == NULL)
464 {
465 return(STATUS_UNSUCCESSFUL);
466 }
467
468 if (FreeType == MEM_RELEASE)
469 {
470 if (MemoryArea->BaseAddress != (*BaseAddress))
471 {
472 return(STATUS_UNSUCCESSFUL);
473 }
474 MmFreeMemoryArea(PsGetCurrentProcess(),
475 BaseAddress,
476 0,
477 TRUE);
478 return(STATUS_SUCCESS);
479 }
480
481 UNIMPLEMENTED;
482 }
483
484 NTSTATUS STDCALL NtLockVirtualMemory(HANDLE ProcessHandle,
485 PVOID BaseAddress,
486 ULONG NumberOfBytesToLock,
487 PULONG NumberOfBytesLocked)
488 {
489 return(ZwLockVirtualMemory(ProcessHandle,
490 BaseAddress,
491 NumberOfBytesToLock,
492 NumberOfBytesLocked));
493 }
494
495 NTSTATUS STDCALL ZwLockVirtualMemory(HANDLE ProcessHandle,
496 PVOID BaseAddress,
497 ULONG NumberOfBytesToLock,
498 PULONG NumberOfBytesLocked)
499 {
500 UNIMPLEMENTED;
501 }
502
503 NTSTATUS STDCALL NtProtectVirtualMemory(IN HANDLE ProcessHandle,
504 IN PVOID BaseAddress,
505 IN ULONG NumberOfBytesToProtect,
506 IN ULONG NewAccessProtection,
507 OUT PULONG OldAccessProtection)
508 {
509 return(ZwProtectVirtualMemory(ProcessHandle,
510 BaseAddress,
511 NumberOfBytesToProtect,
512 NewAccessProtection,
513 OldAccessProtection));
514 }
515
516 VOID MmChangeAreaProtection(PEPROCESS Process,
517 PVOID BaseAddress,
518 ULONG Length,
519 ULONG Protect)
520 {
521 ULONG i;
522
523 for (i=0; i<(Length/PAGESIZE); i++)
524 {
525 if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
526 {
527 MmSetPageProtect(Process, BaseAddress + (i*PAGESIZE), Protect);
528 }
529 }
530 }
531
532 NTSTATUS STDCALL ZwProtectVirtualMemory(IN HANDLE ProcessHandle,
533 IN PVOID BaseAddress,
534 IN ULONG NumberOfBytesToProtect,
535 IN ULONG NewAccessProtection,
536 OUT PULONG OldAccessProtection)
537 {
538 PMEMORY_AREA MemoryArea;
539 PEPROCESS Process;
540 NTSTATUS Status;
541
542 Status = ObReferenceObjectByHandle(ProcessHandle,
543 PROCESS_VM_OPERATION,
544 PsProcessType,
545 UserMode,
546 (PVOID*)(&Process),
547 NULL);
548 if (Status != STATUS_SUCCESS)
549 {
550 DbgPrint("ZwProtectVirtualMemory() = %x\n",Status);
551 return(Status);
552 }
553
554 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
555 if (MemoryArea == NULL)
556 {
557 DbgPrint("ZwProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
558 return(STATUS_UNSUCCESSFUL);
559 }
560
561 *OldAccessProtection = MemoryArea->Attributes;
562
563 if (MemoryArea->BaseAddress == BaseAddress &&
564 MemoryArea->Length == NumberOfBytesToProtect)
565 {
566 MemoryArea->Attributes = NewAccessProtection;
567 }
568 else
569 {
570 MemoryArea = MmSplitMemoryArea(Process,
571 MemoryArea,
572 BaseAddress,
573 NumberOfBytesToProtect,
574 MemoryArea->Type,
575 NewAccessProtection);
576 }
577 MmChangeAreaProtection(Process,BaseAddress,NumberOfBytesToProtect,
578 NewAccessProtection);
579 return(STATUS_SUCCESS);
580 }
581
582
583 NTSTATUS STDCALL NtQueryVirtualMemory(IN HANDLE ProcessHandle,
584 IN PVOID Address,
585 IN IN CINT VirtualMemoryInformationClass,
586 OUT PVOID VirtualMemoryInformation,
587 IN ULONG Length,
588 OUT PULONG ResultLength)
589 {
590 return(ZwQueryVirtualMemory(ProcessHandle,
591 Address,
592 VirtualMemoryInformationClass,
593 VirtualMemoryInformation,
594 Length,
595 ResultLength));
596 }
597
598 NTSTATUS STDCALL ZwQueryVirtualMemory(IN HANDLE ProcessHandle,
599 IN PVOID Address,
600 IN CINT VirtualMemoryInformationClass,
601 OUT PVOID VirtualMemoryInformation,
602 IN ULONG Length,
603 OUT PULONG ResultLength)
604 {
605 UNIMPLEMENTED;
606 }
607
608 NTSTATUS STDCALL NtReadVirtualMemory(IN HANDLE ProcessHandle,
609 IN PVOID BaseAddress,
610 OUT PVOID Buffer,
611 IN ULONG NumberOfBytesToRead,
612 OUT PULONG NumberOfBytesRead)
613 {
614 return(ZwReadVirtualMemory(ProcessHandle,
615 BaseAddress,
616 Buffer,
617 NumberOfBytesToRead,
618 NumberOfBytesRead));
619 }
620
621 NTSTATUS STDCALL ZwReadVirtualMemory(IN HANDLE ProcessHandle,
622 IN PVOID BaseAddress,
623 OUT PVOID Buffer,
624 IN ULONG NumberOfBytesToRead,
625 OUT PULONG NumberOfBytesRead)
626 {
627 PEPROCESS Process;
628 MEMORY_AREA* MemoryArea;
629 ULONG i;
630 NTSTATUS Status;
631 PULONG CurrentEntry;
632
633 Status = ObReferenceObjectByHandle(ProcessHandle,
634 PROCESS_VM_READ,
635 NULL,
636 UserMode,
637 (PVOID*)(&Process),
638 NULL);
639 if (Status != STATUS_SUCCESS)
640 {
641 return(Status);
642 }
643
644 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
645
646 if (MemoryArea == NULL)
647 {
648 return(STATUS_UNSUCCESSFUL);
649 }
650 if (MemoryArea->Length > NumberOfBytesToRead)
651 {
652 NumberOfBytesToRead = MemoryArea->Length;
653 }
654
655 *NumberOfBytesRead = NumberOfBytesToRead;
656
657 for (i=0; i<(NumberOfBytesToRead/PAGESIZE); i++)
658 {
659 CurrentEntry = MmGetPageEntry(Process, BaseAddress + (i*PAGESIZE));
660 RtlCopyMemory(Buffer + (i*PAGESIZE),
661 (PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)),
662 PAGESIZE);
663
664 }
665 return(STATUS_SUCCESS);
666 }
667
668 NTSTATUS STDCALL NtUnlockVirtualMemory(HANDLE ProcessHandle,
669 PVOID BaseAddress,
670 ULONG NumberOfBytesToUnlock,
671 PULONG NumberOfBytesUnlocked OPTIONAL)
672 {
673 return(ZwUnlockVirtualMemory(ProcessHandle,
674 BaseAddress,
675 NumberOfBytesToUnlock,
676 NumberOfBytesUnlocked));
677 }
678
679 NTSTATUS STDCALL ZwUnlockVirtualMemory(HANDLE ProcessHandle,
680 PVOID BaseAddress,
681 ULONG NumberOfBytesToUnlock,
682 PULONG NumberOfBytesUnlocked OPTIONAL)
683 {
684 UNIMPLEMENTED;
685 }
686
687 NTSTATUS STDCALL NtWriteVirtualMemory(IN HANDLE ProcessHandle,
688 IN PVOID BaseAddress,
689 IN PVOID Buffer,
690 IN ULONG NumberOfBytesToWrite,
691 OUT PULONG NumberOfBytesWritten)
692 {
693 return(ZwWriteVirtualMemory(ProcessHandle,
694 BaseAddress,
695 Buffer,
696 NumberOfBytesToWrite,
697 NumberOfBytesWritten));
698 }
699
700 NTSTATUS STDCALL ZwWriteVirtualMemory(IN HANDLE ProcessHandle,
701 IN PVOID BaseAddress,
702 IN PVOID Buffer,
703 IN ULONG NumberOfBytesToWrite,
704 OUT PULONG NumberOfBytesWritten)
705 {
706 PEPROCESS Process;
707 MEMORY_AREA* MemoryArea;
708 ULONG i;
709 NTSTATUS Status;
710 PULONG CurrentEntry;
711
712 Status = ObReferenceObjectByHandle(ProcessHandle,
713 PROCESS_VM_WRITE,
714 NULL,
715 UserMode,
716 (PVOID*)(&Process),
717 NULL);
718 if (Status != STATUS_SUCCESS)
719 {
720 return(Status);
721 }
722
723 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
724
725 if (MemoryArea == NULL)
726 {
727 return(STATUS_UNSUCCESSFUL);
728 }
729 if (MemoryArea->Length > NumberOfBytesToWrite)
730 {
731 NumberOfBytesToWrite = MemoryArea->Length;
732 }
733
734 *NumberOfBytesWritten = NumberOfBytesToWrite;
735
736 for (i=0; i<(NumberOfBytesToWrite/PAGESIZE); i++)
737 {
738 CurrentEntry = MmGetPageEntry(Process, BaseAddress + (i*PAGESIZE));
739 RtlCopyMemory((PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)),
740 Buffer + (i*PAGESIZE),
741 PAGESIZE);
742
743 }
744 return(STATUS_SUCCESS);
745 }
746