This commit was generated by cvs2svn to compensate for changes in r52,
[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 STDCALL NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
251 OUT PVOID *BaseAddress,
252 IN ULONG ZeroBits,
253 IN ULONG RegionSize,
254 IN ULONG AllocationType,
255 IN ULONG Protect)
256 {
257 return(ZwAllocateVirtualMemory(ProcessHandle,
258 BaseAddress,
259 ZeroBits,
260 RegionSize,
261 AllocationType,
262 Protect));
263 }
264
265 NTSTATUS STDCALL ZwAllocateVirtualMemory(IN HANDLE ProcessHandle,
266 OUT PVOID *BaseAddress,
267 IN ULONG ZeroBits,
268 IN ULONG RegionSize,
269 IN ULONG AllocationType,
270 IN ULONG Protect)
271 /*
272 * FUNCTION: Allocates a block of virtual memory in the process address space
273 * ARGUMENTS:
274 * ProcessHandle = The handle of the process which owns the virtual memory
275 * BaseAddress = A pointer to the virtual memory allocated. If you
276 * supply a non zero value the system will try to
277 * allocate the memory at the address supplied. It round
278 * it down to a multiple of the page size.
279 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
280 * that must be zero, ensuring that the memory will be
281 * allocated at a address below a certain value.
282 * RegionSize = The number of bytes to allocate
283 * AllocationType = Indicates the type of virtual memory you like to
284 * allocated, can be one of the values : MEM_COMMIT,
285 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
286 * Protect = Indicates the protection type of the pages allocated, can be
287 * a combination of PAGE_READONLY, PAGE_READWRITE,
288 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
289 * PAGE_NOACCESS
290 * REMARKS:
291 * This function maps to the win32 VirtualAllocEx. Virtual memory is
292 * process based so the protocol starts with a ProcessHandle. I
293 * splitted the functionality of obtaining the actual address and
294 * specifying the start address in two parameters ( BaseAddress and
295 * StartAddress ) The NumberOfBytesAllocated specify the range and the
296 * AllocationType and ProctectionType map to the other two parameters.
297 * RETURNS: Status
298 */
299 {
300 PEPROCESS Process;
301 MEMORY_AREA* MemoryArea;
302 ULONG Type;
303 ULONG i;
304 NTSTATUS Status;
305
306 DbgPrint("ZwAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
307 "ZeroBits %d, RegionSize %d, AllocationType %x, Protect %x)\n",
308 ProcessHandle,*BaseAddress,ZeroBits,RegionSize,AllocationType,
309 Protect);
310
311 Status = ObReferenceObjectByHandle(ProcessHandle,
312 PROCESS_VM_OPERATION,
313 NULL,
314 UserMode,
315 (PVOID*)(&Process),
316 NULL);
317 if (Status != STATUS_SUCCESS)
318 {
319 DbgPrint("ZwAllocateVirtualMemory() = %x\n",Status);
320 return(Status);
321 }
322
323 if (AllocationType & MEM_RESERVE)
324 {
325 Type = MEMORY_AREA_RESERVE;
326 }
327 else
328 {
329 Type = MEMORY_AREA_COMMIT;
330 }
331
332 if ((*BaseAddress) != 0)
333 {
334 MemoryArea = MmOpenMemoryAreaByAddress(Process, *BaseAddress);
335
336 if (MemoryArea != NULL)
337 {
338 if (MemoryArea->BaseAddress == (*BaseAddress) &&
339 MemoryArea->Length == RegionSize)
340 {
341 MemoryArea->Type = Type;
342 MemoryArea->Attributes =Protect;
343 DbgPrint("*BaseAddress %x\n",*BaseAddress);
344 return(STATUS_SUCCESS);
345 }
346
347 MemoryArea = MmSplitMemoryArea(Process,
348 MemoryArea,
349 *BaseAddress,
350 RegionSize,
351 Type,
352 Protect);
353 DbgPrint("*BaseAddress %x\n",*BaseAddress);
354 return(STATUS_SUCCESS);
355 }
356 }
357
358 Status = MmCreateMemoryArea(UserMode,
359 Process,
360 Type,
361 (PULONG)BaseAddress,
362 RegionSize,
363 Protect,
364 &MemoryArea);
365
366 if (Status != STATUS_SUCCESS)
367 {
368 DbgPrint("ZwAllocateVirtualMemory() = %x\n",Status);
369 return(Status);
370 }
371
372 DbgPrint("*BaseAddress %x\n",*BaseAddress);
373
374 return(STATUS_SUCCESS);
375 }
376
377 NTSTATUS STDCALL NtFlushVirtualMemory(IN HANDLE ProcessHandle,
378 IN PVOID BaseAddress,
379 IN ULONG NumberOfBytesToFlush,
380 OUT PULONG NumberOfBytesFlushed OPTIONAL)
381 {
382 return(ZwFlushVirtualMemory(ProcessHandle,
383 BaseAddress,
384 NumberOfBytesToFlush,
385 NumberOfBytesFlushed));
386 }
387
388 NTSTATUS STDCALL ZwFlushVirtualMemory(IN HANDLE ProcessHandle,
389 IN PVOID BaseAddress,
390 IN ULONG NumberOfBytesToFlush,
391 OUT PULONG NumberOfBytesFlushed OPTIONAL)
392
393 /*
394 * FUNCTION: Flushes virtual memory to file
395 * ARGUMENTS:
396 * ProcessHandle = Points to the process that allocated the virtual
397 * memory
398 * BaseAddress = Points to the memory address
399 * NumberOfBytesToFlush = Limits the range to flush,
400 * NumberOfBytesFlushed = Actual number of bytes flushed
401 * RETURNS: Status
402 */
403 {
404 UNIMPLEMENTED;
405 }
406
407 NTSTATUS STDCALL NtFreeVirtualMemory(IN HANDLE ProcessHandle,
408 IN PVOID *BaseAddress,
409 IN ULONG RegionSize,
410 IN ULONG FreeType)
411 {
412 return(ZwFreeVirtualMemory(ProcessHandle,
413 BaseAddress,
414 RegionSize,
415 FreeType));
416 }
417
418 NTSTATUS STDCALL ZwFreeVirtualMemory(IN HANDLE ProcessHandle,
419 IN PVOID *BaseAddress,
420 IN ULONG RegionSize,
421 IN ULONG FreeType)
422
423 /*
424 * FUNCTION: Frees a range of virtual memory
425 * ARGUMENTS:
426 * ProcessHandle = Points to the process that allocated the virtual
427 * memory
428 * BaseAddress = Points to the memory address, rounded down to a
429 * multiple of the pagesize
430 * RegionSize = Limits the range to free, rounded up to a multiple of
431 * the paging size
432 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
433 * RETURNS: Status
434 */
435 {
436 MEMORY_AREA* MemoryArea;
437 NTSTATUS Status;
438 PEPROCESS Process;
439
440 Status = ObReferenceObjectByHandle(ProcessHandle,
441 PROCESS_VM_OPERATION,
442 PsProcessType,
443 UserMode,
444 (PVOID*)(&Process),
445 NULL);
446 if (Status != STATUS_SUCCESS)
447 {
448 DbgPrint("ZwFreeVirtualMemory() = %x\n",Status);
449 return(Status);
450 }
451
452 MemoryArea = MmOpenMemoryAreaByAddress(Process,*BaseAddress);
453 if (MemoryArea == NULL)
454 {
455 return(STATUS_UNSUCCESSFUL);
456 }
457
458 if (FreeType == MEM_RELEASE)
459 {
460 if (MemoryArea->BaseAddress != (*BaseAddress))
461 {
462 return(STATUS_UNSUCCESSFUL);
463 }
464 MmFreeMemoryArea(PsGetCurrentProcess(),
465 BaseAddress,
466 0,
467 TRUE);
468 return(STATUS_SUCCESS);
469 }
470
471 UNIMPLEMENTED;
472 }
473
474 NTSTATUS STDCALL NtLockVirtualMemory(HANDLE ProcessHandle,
475 PVOID BaseAddress,
476 ULONG NumberOfBytesToLock,
477 PULONG NumberOfBytesLocked)
478 {
479 return(ZwLockVirtualMemory(ProcessHandle,
480 BaseAddress,
481 NumberOfBytesToLock,
482 NumberOfBytesLocked));
483 }
484
485 NTSTATUS STDCALL ZwLockVirtualMemory(HANDLE ProcessHandle,
486 PVOID BaseAddress,
487 ULONG NumberOfBytesToLock,
488 PULONG NumberOfBytesLocked)
489 {
490 UNIMPLEMENTED;
491 }
492
493 NTSTATUS STDCALL NtProtectVirtualMemory(IN HANDLE ProcessHandle,
494 IN PVOID BaseAddress,
495 IN ULONG NumberOfBytesToProtect,
496 IN ULONG NewAccessProtection,
497 OUT PULONG OldAccessProtection)
498 {
499 return(ZwProtectVirtualMemory(ProcessHandle,
500 BaseAddress,
501 NumberOfBytesToProtect,
502 NewAccessProtection,
503 OldAccessProtection));
504 }
505
506 VOID MmChangeAreaProtection(PEPROCESS Process,
507 PVOID BaseAddress,
508 ULONG Length,
509 ULONG Protect)
510 {
511 ULONG i;
512
513 for (i=0; i<(Length/PAGESIZE); i++)
514 {
515 if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
516 {
517 MmSetPageProtect(Process, BaseAddress + (i*PAGESIZE), Protect);
518 }
519 }
520 }
521
522 NTSTATUS STDCALL ZwProtectVirtualMemory(IN HANDLE ProcessHandle,
523 IN PVOID BaseAddress,
524 IN ULONG NumberOfBytesToProtect,
525 IN ULONG NewAccessProtection,
526 OUT PULONG OldAccessProtection)
527 {
528 PMEMORY_AREA MemoryArea;
529 PEPROCESS Process;
530 NTSTATUS Status;
531
532 Status = ObReferenceObjectByHandle(ProcessHandle,
533 PROCESS_VM_OPERATION,
534 PsProcessType,
535 UserMode,
536 (PVOID*)(&Process),
537 NULL);
538 if (Status != STATUS_SUCCESS)
539 {
540 DbgPrint("ZwProtectVirtualMemory() = %x\n",Status);
541 return(Status);
542 }
543
544 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
545 if (MemoryArea == NULL)
546 {
547 DbgPrint("ZwProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
548 return(STATUS_UNSUCCESSFUL);
549 }
550
551 *OldAccessProtection = MemoryArea->Attributes;
552
553 if (MemoryArea->BaseAddress == BaseAddress &&
554 MemoryArea->Length == NumberOfBytesToProtect)
555 {
556 MemoryArea->Attributes = NewAccessProtection;
557 }
558 else
559 {
560 MemoryArea = MmSplitMemoryArea(Process,
561 MemoryArea,
562 BaseAddress,
563 NumberOfBytesToProtect,
564 MemoryArea->Type,
565 NewAccessProtection);
566 }
567 MmChangeAreaProtection(Process,BaseAddress,NumberOfBytesToProtect,
568 NewAccessProtection);
569 return(STATUS_SUCCESS);
570 }
571
572
573 NTSTATUS STDCALL NtQueryVirtualMemory(IN HANDLE ProcessHandle,
574 IN PVOID Address,
575 IN IN CINT VirtualMemoryInformationClass,
576 OUT PVOID VirtualMemoryInformation,
577 IN ULONG Length,
578 OUT PULONG ResultLength)
579 {
580 return(ZwQueryVirtualMemory(ProcessHandle,
581 Address,
582 VirtualMemoryInformationClass,
583 VirtualMemoryInformation,
584 Length,
585 ResultLength));
586 }
587
588 NTSTATUS STDCALL ZwQueryVirtualMemory(IN HANDLE ProcessHandle,
589 IN PVOID Address,
590 IN CINT VirtualMemoryInformationClass,
591 OUT PVOID VirtualMemoryInformation,
592 IN ULONG Length,
593 OUT PULONG ResultLength)
594 {
595 UNIMPLEMENTED;
596 }
597
598 NTSTATUS STDCALL NtReadVirtualMemory(IN HANDLE ProcessHandle,
599 IN PVOID BaseAddress,
600 OUT PVOID Buffer,
601 IN ULONG NumberOfBytesToRead,
602 OUT PULONG NumberOfBytesRead)
603 {
604 return(ZwReadVirtualMemory(ProcessHandle,
605 BaseAddress,
606 Buffer,
607 NumberOfBytesToRead,
608 NumberOfBytesRead));
609 }
610
611 NTSTATUS STDCALL ZwReadVirtualMemory(IN HANDLE ProcessHandle,
612 IN PVOID BaseAddress,
613 OUT PVOID Buffer,
614 IN ULONG NumberOfBytesToRead,
615 OUT PULONG NumberOfBytesRead)
616 {
617 PEPROCESS Process;
618 MEMORY_AREA* MemoryArea;
619 ULONG i;
620 NTSTATUS Status;
621 PULONG CurrentEntry;
622
623 Status = ObReferenceObjectByHandle(ProcessHandle,
624 PROCESS_VM_READ,
625 NULL,
626 UserMode,
627 (PVOID*)(&Process),
628 NULL);
629 if (Status != STATUS_SUCCESS)
630 {
631 return(Status);
632 }
633
634 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
635
636 if (MemoryArea == NULL)
637 {
638 return(STATUS_UNSUCCESSFUL);
639 }
640 if (MemoryArea->Length > NumberOfBytesToRead)
641 {
642 NumberOfBytesToRead = MemoryArea->Length;
643 }
644
645 *NumberOfBytesRead = NumberOfBytesToRead;
646
647 for (i=0; i<(NumberOfBytesToRead/PAGESIZE); i++)
648 {
649 CurrentEntry = MmGetPageEntry(Process, BaseAddress + (i*PAGESIZE));
650 RtlCopyMemory(Buffer + (i*PAGESIZE),
651 (PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)),
652 PAGESIZE);
653
654 }
655 return(STATUS_SUCCESS);
656 }
657
658 NTSTATUS STDCALL NtUnlockVirtualMemory(HANDLE ProcessHandle,
659 PVOID BaseAddress,
660 ULONG NumberOfBytesToUnlock,
661 PULONG NumberOfBytesUnlocked OPTIONAL)
662 {
663 return(ZwUnlockVirtualMemory(ProcessHandle,
664 BaseAddress,
665 NumberOfBytesToUnlock,
666 NumberOfBytesUnlocked));
667 }
668
669 NTSTATUS STDCALL ZwUnlockVirtualMemory(HANDLE ProcessHandle,
670 PVOID BaseAddress,
671 ULONG NumberOfBytesToUnlock,
672 PULONG NumberOfBytesUnlocked OPTIONAL)
673 {
674 UNIMPLEMENTED;
675 }
676
677 NTSTATUS STDCALL NtWriteVirtualMemory(IN HANDLE ProcessHandle,
678 IN PVOID BaseAddress,
679 IN PVOID Buffer,
680 IN ULONG NumberOfBytesToWrite,
681 OUT PULONG NumberOfBytesWritten)
682 {
683 return(ZwWriteVirtualMemory(ProcessHandle,
684 BaseAddress,
685 Buffer,
686 NumberOfBytesToWrite,
687 NumberOfBytesWritten));
688 }
689
690 NTSTATUS STDCALL ZwWriteVirtualMemory(IN HANDLE ProcessHandle,
691 IN PVOID BaseAddress,
692 IN PVOID Buffer,
693 IN ULONG NumberOfBytesToWrite,
694 OUT PULONG NumberOfBytesWritten)
695 {
696 PEPROCESS Process;
697 MEMORY_AREA* MemoryArea;
698 ULONG i;
699 NTSTATUS Status;
700 PULONG CurrentEntry;
701
702 Status = ObReferenceObjectByHandle(ProcessHandle,
703 PROCESS_VM_WRITE,
704 NULL,
705 UserMode,
706 (PVOID*)(&Process),
707 NULL);
708 if (Status != STATUS_SUCCESS)
709 {
710 return(Status);
711 }
712
713 MemoryArea = MmOpenMemoryAreaByAddress(Process,BaseAddress);
714
715 if (MemoryArea == NULL)
716 {
717 return(STATUS_UNSUCCESSFUL);
718 }
719 if (MemoryArea->Length > NumberOfBytesToWrite)
720 {
721 NumberOfBytesToWrite = MemoryArea->Length;
722 }
723
724 *NumberOfBytesWritten = NumberOfBytesToWrite;
725
726 for (i=0; i<(NumberOfBytesToWrite/PAGESIZE); i++)
727 {
728 CurrentEntry = MmGetPageEntry(Process, BaseAddress + (i*PAGESIZE));
729 RtlCopyMemory((PVOID)physical_to_linear(PAGE_MASK(*CurrentEntry)),
730 Buffer + (i*PAGESIZE),
731 PAGESIZE);
732
733 }
734 return(STATUS_SUCCESS);
735 }
736