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