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