a622513e13274df90b97a106541ee2a7032894d9
[reactos.git] / reactos / subsystems / mvdm / ntvdm / memory.c
1 /*
2 * COPYRIGHT: GPLv2+ - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/memory.c
5 * PURPOSE: Memory Management
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "ntvdm.h"
14 #include "emulator.h"
15 #include "memory.h"
16
17 /* PRIVATE VARIABLES **********************************************************/
18
19 typedef struct _MEM_HOOK
20 {
21 LIST_ENTRY Entry;
22 HANDLE hVdd;
23 ULONG Count;
24
25 union
26 {
27 PVDD_MEMORY_HANDLER VddHandler;
28
29 struct
30 {
31 PMEMORY_READ_HANDLER FastReadHandler;
32 PMEMORY_WRITE_HANDLER FastWriteHandler;
33 };
34 };
35 } MEM_HOOK, *PMEM_HOOK;
36
37 static LIST_ENTRY HookList;
38 static PMEM_HOOK PageTable[TOTAL_PAGES] = { NULL };
39 static BOOLEAN A20Line = FALSE;
40
41 /* PRIVATE FUNCTIONS **********************************************************/
42
43 static inline VOID
44 MemFastMoveMemory(OUT VOID UNALIGNED *Destination,
45 IN const VOID UNALIGNED *Source,
46 IN SIZE_T Length)
47 {
48 #if 1
49 /*
50 * We use a switch here to detect small moves of memory, as these
51 * constitute the bulk of our moves.
52 * Using RtlMoveMemory for all these small moves would be slow otherwise.
53 */
54 switch (Length)
55 {
56 case 0:
57 return;
58
59 case sizeof(UCHAR):
60 *(PUCHAR)Destination = *(PUCHAR)Source;
61 return;
62
63 case sizeof(USHORT):
64 *(PUSHORT)Destination = *(PUSHORT)Source;
65 return;
66
67 case sizeof(ULONG):
68 *(PULONG)Destination = *(PULONG)Source;
69 return;
70
71 case sizeof(ULONGLONG):
72 *(PULONGLONG)Destination = *(PULONGLONG)Source;
73 return;
74
75 default:
76 #if defined(__GNUC__)
77 __builtin_memmove(Destination, Source, Length);
78 #else
79 RtlMoveMemory(Destination, Source, Length);
80 #endif
81 }
82
83 #else // defined(_MSC_VER)
84
85 PUCHAR Dest = (PUCHAR)Destination;
86 PUCHAR Src = (PUCHAR)Source;
87
88 SIZE_T Count, NewSize = Length;
89
90 /* Move dword */
91 Count = NewSize >> 2; // NewSize / sizeof(ULONG);
92 NewSize = NewSize & 3; // NewSize % sizeof(ULONG);
93 __movsd(Dest, Src, Count);
94 Dest += Count << 2; // Count * sizeof(ULONG);
95 Src += Count << 2;
96
97 /* Move word */
98 Count = NewSize >> 1; // NewSize / sizeof(USHORT);
99 NewSize = NewSize & 1; // NewSize % sizeof(USHORT);
100 __movsw(Dest, Src, Count);
101 Dest += Count << 1; // Count * sizeof(USHORT);
102 Src += Count << 1;
103
104 /* Move byte */
105 Count = NewSize; // NewSize / sizeof(UCHAR);
106 // NewSize = NewSize; // NewSize % sizeof(UCHAR);
107 __movsb(Dest, Src, Count);
108
109 #endif
110 }
111
112 static inline VOID
113 ReadPage(PMEM_HOOK Hook, ULONG Address, PVOID Buffer, ULONG Size)
114 {
115 if (Hook && !Hook->hVdd && Hook->FastReadHandler)
116 {
117 Hook->FastReadHandler(Address, REAL_TO_PHYS(Address), Size);
118 }
119
120 MemFastMoveMemory(Buffer, REAL_TO_PHYS(Address), Size);
121 }
122
123 static inline VOID
124 WritePage(PMEM_HOOK Hook, ULONG Address, PVOID Buffer, ULONG Size)
125 {
126 if (!Hook
127 || Hook->hVdd
128 || !Hook->FastWriteHandler
129 || Hook->FastWriteHandler(Address, Buffer, Size))
130 {
131 MemFastMoveMemory(REAL_TO_PHYS(Address), Buffer, Size);
132 }
133 }
134
135 /* PUBLIC FUNCTIONS ***********************************************************/
136
137 VOID FASTCALL EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
138 {
139 ULONG i, Offset, Length;
140 ULONG FirstPage, LastPage;
141
142 UNREFERENCED_PARAMETER(State);
143
144 /* Mirror 0x000FFFF0 at 0xFFFFFFF0 */
145 if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
146
147 /* If the A20 line is disabled, mask bit 20 */
148 if (!A20Line) Address &= ~(1 << 20);
149
150 if ((Address + Size - 1) >= MAX_ADDRESS)
151 {
152 ULONG ExtraStart = (Address < MAX_ADDRESS) ? MAX_ADDRESS - Address : 0;
153
154 /* Fill the memory that was above the limit with 0xFF */
155 RtlFillMemory((PVOID)((ULONG_PTR)Buffer + ExtraStart), Size - ExtraStart, 0xFF);
156
157 if (Address < MAX_ADDRESS) Size = MAX_ADDRESS - Address;
158 else return;
159 }
160
161 FirstPage = Address >> 12;
162 LastPage = (Address + Size - 1) >> 12;
163
164 if (FirstPage == LastPage)
165 {
166 ReadPage(PageTable[FirstPage], Address, Buffer, Size);
167 }
168 else
169 {
170 for (i = FirstPage; i <= LastPage; i++)
171 {
172 Offset = (i == FirstPage) ? (Address & (PAGE_SIZE - 1)) : 0;
173 Length = ((i == LastPage) ? (Address + Size - (LastPage << 12)) : PAGE_SIZE) - Offset;
174
175 ReadPage(PageTable[i], (i << 12) + Offset, Buffer, Length);
176 Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
177 }
178 }
179 }
180
181 VOID FASTCALL EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
182 {
183 ULONG i, Offset, Length;
184 ULONG FirstPage, LastPage;
185
186 UNREFERENCED_PARAMETER(State);
187
188 /* If the A20 line is disabled, mask bit 20 */
189 if (!A20Line) Address &= ~(1 << 20);
190
191 if (Address >= MAX_ADDRESS) return;
192 Size = min(Size, MAX_ADDRESS - Address);
193
194 FirstPage = Address >> 12;
195 LastPage = (Address + Size - 1) >> 12;
196
197 if (FirstPage == LastPage)
198 {
199 WritePage(PageTable[FirstPage], Address, Buffer, Size);
200 }
201 else
202 {
203 for (i = FirstPage; i <= LastPage; i++)
204 {
205 Offset = (i == FirstPage) ? (Address & (PAGE_SIZE - 1)) : 0;
206 Length = ((i == LastPage) ? (Address + Size - (LastPage << 12)) : PAGE_SIZE) - Offset;
207
208 WritePage(PageTable[i], (i << 12) + Offset, Buffer, Length);
209 Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
210 }
211 }
212 }
213
214 VOID FASTCALL EmulatorCopyMemory(PFAST486_STATE State, ULONG DestAddress, ULONG SrcAddress, ULONG Size)
215 {
216 /*
217 * Guest-to-guest memory copy
218 */
219
220 // FIXME: This is a temporary implementation of a more useful functionality
221 // which should be a merge of EmulatorReadMemory & EmulatorWriteMemory without
222 // any local external buffer.
223 // NOTE: Process heap is by default serialized (unless one specifies it shouldn't).
224 static BYTE StaticBuffer[8192]; // Smallest static buffer we can use.
225 static PVOID HeapBuffer = NULL; // Always-growing heap buffer. Use it in case StaticBuffer is too small.
226 static ULONG HeapBufferSize = 0;
227 PVOID LocalBuffer; // Points to either StaticBuffer or HeapBuffer
228
229 if (Size <= sizeof(StaticBuffer))
230 {
231 /* Use the static buffer */
232 LocalBuffer = StaticBuffer;
233 }
234 else if (/* sizeof(StaticBuffer) <= Size && */ Size <= HeapBufferSize)
235 {
236 /* Use the heap buffer */
237 ASSERT(HeapBufferSize > 0 && HeapBuffer != NULL);
238 LocalBuffer = HeapBuffer;
239 }
240 else // if (Size > HeapBufferSize)
241 {
242 /* Enlarge the heap buffer and use it */
243
244 if (HeapBuffer == NULL)
245 {
246 /* First allocation */
247 LocalBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
248 }
249 else
250 {
251 /* Reallocation */
252 LocalBuffer = RtlReAllocateHeap(RtlGetProcessHeap(), 0 /* HEAP_GENERATE_EXCEPTIONS */, HeapBuffer, Size);
253 }
254 ASSERT(LocalBuffer != NULL); // We must succeed! TODO: Handle it more properly.
255 HeapBuffer = LocalBuffer; // HeapBuffer is now reallocated.
256 HeapBufferSize = Size;
257 }
258
259 /* Perform memory copy */
260 EmulatorReadMemory( State, SrcAddress , LocalBuffer, Size);
261 EmulatorWriteMemory(State, DestAddress, LocalBuffer, Size);
262
263 // if (LocalBuffer != StaticBuffer)
264 // RtlFreeHeap(RtlGetProcessHeap(), 0, LocalBuffer);
265
266 // Note that we don't free HeapBuffer since it's an always-growing buffer.
267 // It is freed when NTVDM termiantes.
268 }
269
270 VOID EmulatorSetA20(BOOLEAN Enabled)
271 {
272 A20Line = Enabled;
273 }
274
275 BOOLEAN EmulatorGetA20(VOID)
276 {
277 return A20Line;
278 }
279
280 VOID
281 MemExceptionHandler(ULONG FaultAddress, BOOLEAN Writing)
282 {
283 PMEM_HOOK Hook = PageTable[FaultAddress >> 12];
284 DPRINT("The memory at 0x%08X could not be %s.\n", FaultAddress, Writing ? "written" : "read");
285
286 /* Exceptions are only supposed to happen when using VDD-style memory hooks */
287 ASSERT(FaultAddress < MAX_ADDRESS && Hook != NULL && Hook->hVdd != NULL);
288
289 /* Call the VDD handler */
290 Hook->VddHandler(REAL_TO_PHYS(FaultAddress), (ULONG)Writing);
291 }
292
293 BOOL
294 MemInstallFastMemoryHook(PVOID Address,
295 ULONG Size,
296 PMEMORY_READ_HANDLER ReadHandler,
297 PMEMORY_WRITE_HANDLER WriteHandler)
298 {
299 PMEM_HOOK Hook;
300 ULONG i;
301 ULONG FirstPage = (ULONG_PTR)Address >> 12;
302 ULONG LastPage = ((ULONG_PTR)Address + Size - 1) >> 12;
303 PLIST_ENTRY Pointer;
304
305 /* Make sure none of these pages are already allocated */
306 for (i = FirstPage; i <= LastPage; i++)
307 {
308 if (PageTable[i] != NULL) return FALSE;
309 }
310
311 for (Pointer = HookList.Flink; Pointer != &HookList; Pointer = Pointer->Flink)
312 {
313 Hook = CONTAINING_RECORD(Pointer, MEM_HOOK, Entry);
314
315 if (Hook->hVdd == NULL
316 && Hook->FastReadHandler == ReadHandler
317 && Hook->FastWriteHandler == WriteHandler)
318 {
319 break;
320 }
321 }
322
323 if (Pointer == &HookList)
324 {
325 /* Create and initialize a new hook entry... */
326 Hook = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Hook));
327 if (Hook == NULL) return FALSE;
328
329 Hook->hVdd = NULL;
330 Hook->Count = 0;
331 Hook->FastReadHandler = ReadHandler;
332 Hook->FastWriteHandler = WriteHandler;
333
334 /* ... and add it to the list of hooks */
335 InsertTailList(&HookList, &Hook->Entry);
336 }
337
338 /* Increase the number of pages this hook has */
339 Hook->Count += LastPage - FirstPage + 1;
340
341 /* Add the hook entry to the page table */
342 for (i = FirstPage; i <= LastPage; i++) PageTable[i] = Hook;
343
344 return TRUE;
345 }
346
347 BOOL
348 MemRemoveFastMemoryHook(PVOID Address, ULONG Size)
349 {
350 PMEM_HOOK Hook;
351 ULONG i;
352 ULONG FirstPage = (ULONG_PTR)Address >> 12;
353 ULONG LastPage = ((ULONG_PTR)Address + Size - 1) >> 12;
354
355 if (Size == 0) return FALSE;
356
357 for (i = FirstPage; i <= LastPage; i++)
358 {
359 Hook = PageTable[i];
360 if (Hook == NULL || Hook->hVdd != NULL) continue;
361
362 if (--Hook->Count == 0)
363 {
364 /* This hook has no more pages */
365 RemoveEntryList(&Hook->Entry);
366 RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
367 }
368
369 PageTable[i] = NULL;
370 }
371
372 return TRUE;
373 }
374
375 BOOLEAN
376 MemQueryMemoryZone(ULONG StartAddress, PULONG Length, PBOOLEAN Hooked)
377 {
378 ULONG Page = StartAddress >> 12;
379 if (Page >= TOTAL_PAGES) return FALSE;
380
381 *Length = 0;
382 *Hooked = PageTable[Page] != NULL;
383
384 while (Page < TOTAL_PAGES && (PageTable[Page] != NULL) == *Hooked)
385 {
386 *Length += PAGE_SIZE;
387 Page++;
388 }
389
390 return TRUE;
391 }
392
393 PBYTE
394 WINAPI
395 Sim32pGetVDMPointer(IN ULONG Address,
396 IN BOOLEAN ProtectedMode)
397 {
398 // FIXME
399 UNREFERENCED_PARAMETER(ProtectedMode);
400
401 /*
402 * HIWORD(Address) == Segment (if ProtectedMode == FALSE)
403 * or Selector (if ProtectedMode == TRUE )
404 * LOWORD(Address) == Offset
405 */
406 return (PBYTE)FAR_POINTER(Address);
407 }
408
409 PBYTE
410 WINAPI
411 MGetVdmPointer(IN ULONG Address,
412 IN ULONG Size,
413 IN BOOLEAN ProtectedMode)
414 {
415 UNREFERENCED_PARAMETER(Size);
416 return Sim32pGetVDMPointer(Address, ProtectedMode);
417 }
418
419 PVOID
420 WINAPI
421 VdmMapFlat(IN USHORT Segment,
422 IN ULONG Offset,
423 IN VDM_MODE Mode)
424 {
425 // FIXME
426 UNREFERENCED_PARAMETER(Mode);
427
428 return SEG_OFF_TO_PTR(Segment, Offset);
429 }
430
431 #ifndef VdmFlushCache
432
433 BOOL
434 WINAPI
435 VdmFlushCache(IN USHORT Segment,
436 IN ULONG Offset,
437 IN ULONG Size,
438 IN VDM_MODE Mode)
439 {
440 // FIXME
441 UNIMPLEMENTED;
442 return TRUE;
443 }
444
445 #endif
446
447 #ifndef VdmUnmapFlat
448
449 BOOL
450 WINAPI
451 VdmUnmapFlat(IN USHORT Segment,
452 IN ULONG Offset,
453 IN PVOID Buffer,
454 IN VDM_MODE Mode)
455 {
456 // FIXME
457 UNIMPLEMENTED;
458 return TRUE;
459 }
460
461 #endif
462
463 BOOL
464 WINAPI
465 VDDInstallMemoryHook(IN HANDLE hVdd,
466 IN PVOID pStart,
467 IN DWORD dwCount,
468 IN PVDD_MEMORY_HANDLER MemoryHandler)
469 {
470 NTSTATUS Status;
471 PMEM_HOOK Hook;
472 ULONG i;
473 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(pStart) >> 12;
474 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(pStart) + dwCount - 1) >> 12;
475 PVOID Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
476 SIZE_T Size = (LastPage - FirstPage + 1) * PAGE_SIZE;
477 PLIST_ENTRY Pointer;
478
479 /* Check validity of the VDD handle */
480 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
481 {
482 SetLastError(ERROR_INVALID_PARAMETER);
483 return FALSE;
484 }
485
486 if (dwCount == 0) return FALSE;
487
488 /* Make sure none of these pages are already allocated */
489 for (i = FirstPage; i <= LastPage; i++)
490 {
491 if (PageTable[i] != NULL) return FALSE;
492 }
493
494 for (Pointer = HookList.Flink; Pointer != &HookList; Pointer = Pointer->Flink)
495 {
496 Hook = CONTAINING_RECORD(Pointer, MEM_HOOK, Entry);
497 if (Hook->hVdd == hVdd && Hook->VddHandler == MemoryHandler) break;
498 }
499
500 if (Pointer == &HookList)
501 {
502 /* Create and initialize a new hook entry... */
503 Hook = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Hook));
504 if (Hook == NULL)
505 {
506 SetLastError(ERROR_OUTOFMEMORY);
507 return FALSE;
508 }
509
510 Hook->hVdd = hVdd;
511 Hook->Count = 0;
512 Hook->VddHandler = MemoryHandler;
513
514 /* ... and add it to the list of hooks */
515 InsertTailList(&HookList, &Hook->Entry);
516 }
517
518 /* Decommit the pages */
519 Status = NtFreeVirtualMemory(NtCurrentProcess(),
520 &Address,
521 &Size,
522 MEM_DECOMMIT);
523 if (!NT_SUCCESS(Status))
524 {
525 if (Pointer == &HookList)
526 {
527 RemoveEntryList(&Hook->Entry);
528 RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
529 }
530
531 return FALSE;
532 }
533
534 /* Increase the number of pages this hook has */
535 Hook->Count += LastPage - FirstPage + 1;
536
537 /* Add the hook entry to the page table */
538 for (i = FirstPage; i <= LastPage; i++) PageTable[i] = Hook;
539
540 return TRUE;
541 }
542
543 BOOL
544 WINAPI
545 VDDDeInstallMemoryHook(IN HANDLE hVdd,
546 IN PVOID pStart,
547 IN DWORD dwCount)
548 {
549 NTSTATUS Status;
550 PMEM_HOOK Hook;
551 ULONG i;
552 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(pStart) >> 12;
553 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(pStart) + dwCount - 1) >> 12;
554 PVOID Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
555 SIZE_T Size = (LastPage - FirstPage + 1) * PAGE_SIZE;
556
557 /* Check validity of the VDD handle */
558 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
559 {
560 SetLastError(ERROR_INVALID_PARAMETER);
561 return FALSE;
562 }
563
564 if (dwCount == 0) return FALSE;
565
566 /* Commit the pages */
567 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
568 &Address,
569 0,
570 &Size,
571 MEM_COMMIT,
572 PAGE_READWRITE);
573 if (!NT_SUCCESS(Status)) return FALSE;
574
575 for (i = FirstPage; i <= LastPage; i++)
576 {
577 Hook = PageTable[i];
578 if (Hook == NULL) continue;
579
580 if (Hook->hVdd != hVdd)
581 {
582 DPRINT1("VDDDeInstallMemoryHook: Page %u owned by someone else.\n", i);
583 continue;
584 }
585
586 if (--Hook->Count == 0)
587 {
588 /* This hook has no more pages */
589 RemoveEntryList(&Hook->Entry);
590 RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
591 }
592
593 PageTable[i] = NULL;
594 }
595
596 return TRUE;
597 }
598
599 BOOL
600 WINAPI
601 VDDAllocMem(IN HANDLE hVdd,
602 IN PVOID Address,
603 IN ULONG Size)
604 {
605 NTSTATUS Status;
606 PMEM_HOOK Hook;
607 ULONG i;
608 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(Address) >> 12;
609 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(Address) + Size - 1) >> 12;
610 SIZE_T RealSize = (LastPage - FirstPage + 1) * PAGE_SIZE;
611
612 /* Check validity of the VDD handle */
613 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
614 {
615 SetLastError(ERROR_INVALID_PARAMETER);
616 return FALSE;
617 }
618
619 if (Size == 0) return FALSE;
620
621 /* Fixup the address */
622 Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
623
624 /* Be sure that all the region is held by the VDD */
625 for (i = FirstPage; i <= LastPage; i++)
626 {
627 Hook = PageTable[i];
628 if (Hook == NULL) return FALSE;
629
630 if (Hook->hVdd != hVdd)
631 {
632 DPRINT1("VDDAllocMem: Page %u owned by someone else.\n", i);
633 return FALSE;
634 }
635 }
636
637 /* OK, all the range is held by the VDD. Commit the pages. */
638 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
639 &Address,
640 0,
641 &RealSize,
642 MEM_COMMIT,
643 PAGE_READWRITE);
644 return NT_SUCCESS(Status);
645 }
646
647 BOOL
648 WINAPI
649 VDDFreeMem(IN HANDLE hVdd,
650 IN PVOID Address,
651 IN ULONG Size)
652 {
653 NTSTATUS Status;
654 PMEM_HOOK Hook;
655 ULONG i;
656 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(Address) >> 12;
657 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(Address) + Size - 1) >> 12;
658 SIZE_T RealSize = (LastPage - FirstPage + 1) * PAGE_SIZE;
659
660 /* Check validity of the VDD handle */
661 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
662 {
663 SetLastError(ERROR_INVALID_PARAMETER);
664 return FALSE;
665 }
666
667 if (Size == 0) return FALSE;
668
669 /* Fixup the address */
670 Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
671
672 /* Be sure that all the region is held by the VDD */
673 for (i = FirstPage; i <= LastPage; i++)
674 {
675 Hook = PageTable[i];
676 if (Hook == NULL) return FALSE;
677
678 if (Hook->hVdd != hVdd)
679 {
680 DPRINT1("VDDFreeMem: Page %u owned by someone else.\n", i);
681 return FALSE;
682 }
683 }
684
685 /* OK, all the range is held by the VDD. Decommit the pages. */
686 Status = NtFreeVirtualMemory(NtCurrentProcess(),
687 &Address,
688 &RealSize,
689 MEM_DECOMMIT);
690 return NT_SUCCESS(Status);
691 }
692
693 BOOL
694 WINAPI
695 VDDIncludeMem(IN HANDLE hVdd,
696 IN PVOID Address,
697 IN ULONG Size)
698 {
699 // FIXME
700 UNIMPLEMENTED;
701 return FALSE;
702 }
703
704 BOOL
705 WINAPI
706 VDDExcludeMem(IN HANDLE hVdd,
707 IN PVOID Address,
708 IN ULONG Size)
709 {
710 // FIXME
711 UNIMPLEMENTED;
712 return FALSE;
713 }
714
715
716
717 BOOLEAN
718 MemInitialize(VOID)
719 {
720 NTSTATUS Status;
721 SIZE_T MemorySize = MAX_ADDRESS; // See: kernel32/client/vdm.c!BaseGetVdmConfigInfo
722
723 InitializeListHead(&HookList);
724
725 #ifndef STANDALONE
726
727 /*
728 * The reserved region starts from the very first page.
729 * We need to commit the reserved first 16 MB virtual address.
730 *
731 * NOTE: NULL has another signification for NtAllocateVirtualMemory.
732 */
733 BaseAddress = (PVOID)1;
734
735 /*
736 * Since to get NULL, we allocated from 0x1, account for this.
737 * See also: kernel32/client/proc.c!CreateProcessInternalW
738 */
739 MemorySize -= 1;
740
741 #else
742
743 /* Allocate it anywhere */
744 BaseAddress = NULL;
745
746 #endif
747
748 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
749 &BaseAddress,
750 0,
751 &MemorySize,
752 #ifndef STANDALONE
753 MEM_COMMIT,
754 #else
755 MEM_RESERVE | MEM_COMMIT,
756 #endif
757 PAGE_EXECUTE_READWRITE);
758 if (!NT_SUCCESS(Status))
759 {
760 wprintf(L"FATAL: Failed to commit VDM memory, Status 0x%08lx\n", Status);
761 return FALSE;
762 }
763
764 #ifndef STANDALONE
765 ASSERT(BaseAddress == NULL);
766 #endif
767
768 /*
769 * For diagnostics purposes, we fill the memory with INT 0x03 codes
770 * so that if a program wants to execute random code in memory, we can
771 * retrieve the exact CS:IP where the problem happens.
772 */
773 RtlFillMemory(BaseAddress, MAX_ADDRESS, 0xCC);
774 return TRUE;
775 }
776
777 VOID
778 MemCleanup(VOID)
779 {
780 NTSTATUS Status;
781 SIZE_T MemorySize = MAX_ADDRESS;
782 PLIST_ENTRY Pointer;
783
784 while (!IsListEmpty(&HookList))
785 {
786 Pointer = RemoveHeadList(&HookList);
787 RtlFreeHeap(RtlGetProcessHeap(), 0, CONTAINING_RECORD(Pointer, MEM_HOOK, Entry));
788 }
789
790 /* Decommit the VDM memory */
791 Status = NtFreeVirtualMemory(NtCurrentProcess(),
792 &BaseAddress,
793 &MemorySize,
794 #ifndef STANDALONE
795 MEM_DECOMMIT
796 #else
797 MEM_RELEASE
798 #endif
799 );
800 if (!NT_SUCCESS(Status))
801 {
802 DPRINT1("NTVDM: Failed to decommit VDM memory, Status 0x%08lx\n", Status);
803 }
804 }
805
806 /* EOF */