49a14eb144a28dc9c1bea31cf3cbbe0e74b86aad
[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: 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
113 inline
114 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
126 inline
127 VOID
128 WritePage(PMEM_HOOK Hook, ULONG Address, PVOID Buffer, ULONG Size)
129 {
130 if (!Hook
131 || Hook->hVdd
132 || !Hook->FastWriteHandler
133 || Hook->FastWriteHandler(Address, Buffer, Size))
134 {
135 MemFastMoveMemory(REAL_TO_PHYS(Address), Buffer, Size);
136 }
137 }
138
139 /* PUBLIC FUNCTIONS ***********************************************************/
140
141 VOID FASTCALL EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
142 {
143 ULONG i, Offset, Length;
144 ULONG FirstPage, LastPage;
145
146 UNREFERENCED_PARAMETER(State);
147
148 /* Mirror 0x000FFFF0 at 0xFFFFFFF0 */
149 if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
150
151 /* If the A20 line is disabled, mask bit 20 */
152 if (!A20Line) Address &= ~(1 << 20);
153
154 if ((Address + Size - 1) >= MAX_ADDRESS)
155 {
156 ULONG ExtraStart = (Address < MAX_ADDRESS) ? MAX_ADDRESS - Address : 0;
157
158 /* Fill the memory that was above the limit with 0xFF */
159 RtlFillMemory((PVOID)((ULONG_PTR)Buffer + ExtraStart), Size - ExtraStart, 0xFF);
160
161 if (Address < MAX_ADDRESS) Size = MAX_ADDRESS - Address;
162 else return;
163 }
164
165 FirstPage = Address >> 12;
166 LastPage = (Address + Size - 1) >> 12;
167
168 if (FirstPage == LastPage)
169 {
170 ReadPage(PageTable[FirstPage], Address, Buffer, Size);
171 }
172 else
173 {
174 for (i = FirstPage; i <= LastPage; i++)
175 {
176 Offset = (i == FirstPage) ? (Address & (PAGE_SIZE - 1)) : 0;
177 Length = ((i == LastPage) ? (Address + Size - (LastPage << 12)) : PAGE_SIZE) - Offset;
178
179 ReadPage(PageTable[i], (i << 12) + Offset, Buffer, Length);
180 Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
181 }
182 }
183 }
184
185 VOID FASTCALL EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
186 {
187 ULONG i, Offset, Length;
188 ULONG FirstPage, LastPage;
189
190 UNREFERENCED_PARAMETER(State);
191
192 /* If the A20 line is disabled, mask bit 20 */
193 if (!A20Line) Address &= ~(1 << 20);
194
195 if (Address >= MAX_ADDRESS) return;
196 Size = min(Size, MAX_ADDRESS - Address);
197
198 FirstPage = Address >> 12;
199 LastPage = (Address + Size - 1) >> 12;
200
201 if (FirstPage == LastPage)
202 {
203 WritePage(PageTable[FirstPage], Address, Buffer, Size);
204 }
205 else
206 {
207 for (i = FirstPage; i <= LastPage; i++)
208 {
209 Offset = (i == FirstPage) ? (Address & (PAGE_SIZE - 1)) : 0;
210 Length = ((i == LastPage) ? (Address + Size - (LastPage << 12)) : PAGE_SIZE) - Offset;
211
212 WritePage(PageTable[i], (i << 12) + Offset, Buffer, Length);
213 Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
214 }
215 }
216 }
217
218 VOID EmulatorSetA20(BOOLEAN Enabled)
219 {
220 A20Line = Enabled;
221 }
222
223 BOOLEAN EmulatorGetA20(VOID)
224 {
225 return A20Line;
226 }
227
228 VOID
229 MemExceptionHandler(ULONG FaultAddress, BOOLEAN Writing)
230 {
231 PMEM_HOOK Hook = PageTable[FaultAddress >> 12];
232 DPRINT("The memory at 0x%08X could not be %s.\n", FaultAddress, Writing ? "written" : "read");
233
234 /* Exceptions are only supposed to happen when using VDD-style memory hooks */
235 ASSERT(FaultAddress < MAX_ADDRESS && Hook != NULL && Hook->hVdd != NULL);
236
237 /* Call the VDD handler */
238 Hook->VddHandler(REAL_TO_PHYS(FaultAddress), (ULONG)Writing);
239 }
240
241 BOOL
242 MemInstallFastMemoryHook(PVOID Address,
243 ULONG Size,
244 PMEMORY_READ_HANDLER ReadHandler,
245 PMEMORY_WRITE_HANDLER WriteHandler)
246 {
247 PMEM_HOOK Hook;
248 ULONG i;
249 ULONG FirstPage = (ULONG_PTR)Address >> 12;
250 ULONG LastPage = ((ULONG_PTR)Address + Size - 1) >> 12;
251 PLIST_ENTRY Pointer;
252
253 /* Make sure none of these pages are already allocated */
254 for (i = FirstPage; i <= LastPage; i++)
255 {
256 if (PageTable[i] != NULL) return FALSE;
257 }
258
259 for (Pointer = HookList.Flink; Pointer != &HookList; Pointer = Pointer->Flink)
260 {
261 Hook = CONTAINING_RECORD(Pointer, MEM_HOOK, Entry);
262
263 if (Hook->hVdd == NULL
264 && Hook->FastReadHandler == ReadHandler
265 && Hook->FastWriteHandler == WriteHandler)
266 {
267 break;
268 }
269 }
270
271 if (Pointer == &HookList)
272 {
273 /* Create and initialize a new hook entry... */
274 Hook = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Hook));
275 if (Hook == NULL) return FALSE;
276
277 Hook->hVdd = NULL;
278 Hook->Count = 0;
279 Hook->FastReadHandler = ReadHandler;
280 Hook->FastWriteHandler = WriteHandler;
281
282 /* ... and add it to the list of hooks */
283 InsertTailList(&HookList, &Hook->Entry);
284 }
285
286 /* Increase the number of pages this hook has */
287 Hook->Count += LastPage - FirstPage + 1;
288
289 /* Add the hook entry to the page table */
290 for (i = FirstPage; i <= LastPage; i++) PageTable[i] = Hook;
291
292 return TRUE;
293 }
294
295 BOOL
296 MemRemoveFastMemoryHook(PVOID Address, ULONG Size)
297 {
298 PMEM_HOOK Hook;
299 ULONG i;
300 ULONG FirstPage = (ULONG_PTR)Address >> 12;
301 ULONG LastPage = ((ULONG_PTR)Address + Size - 1) >> 12;
302
303 if (Size == 0) return FALSE;
304
305 for (i = FirstPage; i <= LastPage; i++)
306 {
307 Hook = PageTable[i];
308 if (Hook == NULL || Hook->hVdd != NULL) continue;
309
310 if (--Hook->Count == 0)
311 {
312 /* This hook has no more pages */
313 RemoveEntryList(&Hook->Entry);
314 RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
315 }
316
317 PageTable[i] = NULL;
318 }
319
320 return TRUE;
321 }
322
323 BOOLEAN
324 MemQueryMemoryZone(ULONG StartAddress, PULONG Length, PBOOLEAN Hooked)
325 {
326 ULONG Page = StartAddress >> 12;
327 if (Page >= TOTAL_PAGES) return FALSE;
328
329 *Length = 0;
330 *Hooked = PageTable[Page] != NULL;
331
332 while (Page < TOTAL_PAGES && (PageTable[Page] != NULL) == *Hooked)
333 {
334 *Length += PAGE_SIZE;
335 Page++;
336 }
337
338 return TRUE;
339 }
340
341 PBYTE
342 WINAPI
343 Sim32pGetVDMPointer(IN ULONG Address,
344 IN BOOLEAN ProtectedMode)
345 {
346 // FIXME
347 UNREFERENCED_PARAMETER(ProtectedMode);
348
349 /*
350 * HIWORD(Address) == Segment (if ProtectedMode == FALSE)
351 * or Selector (if ProtectedMode == TRUE )
352 * LOWORD(Address) == Offset
353 */
354 return (PBYTE)FAR_POINTER(Address);
355 }
356
357 PBYTE
358 WINAPI
359 MGetVdmPointer(IN ULONG Address,
360 IN ULONG Size,
361 IN BOOLEAN ProtectedMode)
362 {
363 UNREFERENCED_PARAMETER(Size);
364 return Sim32pGetVDMPointer(Address, ProtectedMode);
365 }
366
367 PVOID
368 WINAPI
369 VdmMapFlat(IN USHORT Segment,
370 IN ULONG Offset,
371 IN VDM_MODE Mode)
372 {
373 // FIXME
374 UNREFERENCED_PARAMETER(Mode);
375
376 return SEG_OFF_TO_PTR(Segment, Offset);
377 }
378
379 #ifndef VdmFlushCache
380
381 BOOL
382 WINAPI
383 VdmFlushCache(IN USHORT Segment,
384 IN ULONG Offset,
385 IN ULONG Size,
386 IN VDM_MODE Mode)
387 {
388 // FIXME
389 UNIMPLEMENTED;
390 return TRUE;
391 }
392
393 #endif
394
395 #ifndef VdmUnmapFlat
396
397 BOOL
398 WINAPI
399 VdmUnmapFlat(IN USHORT Segment,
400 IN ULONG Offset,
401 IN PVOID Buffer,
402 IN VDM_MODE Mode)
403 {
404 // FIXME
405 UNIMPLEMENTED;
406 return TRUE;
407 }
408
409 #endif
410
411 BOOL
412 WINAPI
413 VDDInstallMemoryHook(IN HANDLE hVdd,
414 IN PVOID pStart,
415 IN DWORD dwCount,
416 IN PVDD_MEMORY_HANDLER MemoryHandler)
417 {
418 NTSTATUS Status;
419 PMEM_HOOK Hook;
420 ULONG i;
421 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(pStart) >> 12;
422 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(pStart) + dwCount - 1) >> 12;
423 PVOID Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
424 SIZE_T Size = (LastPage - FirstPage + 1) * PAGE_SIZE;
425 PLIST_ENTRY Pointer;
426
427 /* Check validity of the VDD handle */
428 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
429 {
430 SetLastError(ERROR_INVALID_PARAMETER);
431 return FALSE;
432 }
433
434 if (dwCount == 0) return FALSE;
435
436 /* Make sure none of these pages are already allocated */
437 for (i = FirstPage; i <= LastPage; i++)
438 {
439 if (PageTable[i] != NULL) return FALSE;
440 }
441
442 for (Pointer = HookList.Flink; Pointer != &HookList; Pointer = Pointer->Flink)
443 {
444 Hook = CONTAINING_RECORD(Pointer, MEM_HOOK, Entry);
445 if (Hook->hVdd == hVdd && Hook->VddHandler == MemoryHandler) break;
446 }
447
448 if (Pointer == &HookList)
449 {
450 /* Create and initialize a new hook entry... */
451 Hook = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Hook));
452 if (Hook == NULL)
453 {
454 SetLastError(ERROR_OUTOFMEMORY);
455 return FALSE;
456 }
457
458 Hook->hVdd = hVdd;
459 Hook->Count = 0;
460 Hook->VddHandler = MemoryHandler;
461
462 /* ... and add it to the list of hooks */
463 InsertTailList(&HookList, &Hook->Entry);
464 }
465
466 /* Decommit the pages */
467 Status = NtFreeVirtualMemory(NtCurrentProcess(),
468 &Address,
469 &Size,
470 MEM_DECOMMIT);
471 if (!NT_SUCCESS(Status))
472 {
473 if (Pointer == &HookList)
474 {
475 RemoveEntryList(&Hook->Entry);
476 RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
477 }
478
479 return FALSE;
480 }
481
482 /* Increase the number of pages this hook has */
483 Hook->Count += LastPage - FirstPage + 1;
484
485 /* Add the hook entry to the page table */
486 for (i = FirstPage; i <= LastPage; i++) PageTable[i] = Hook;
487
488 return TRUE;
489 }
490
491 BOOL
492 WINAPI
493 VDDDeInstallMemoryHook(IN HANDLE hVdd,
494 IN PVOID pStart,
495 IN DWORD dwCount)
496 {
497 NTSTATUS Status;
498 PMEM_HOOK Hook;
499 ULONG i;
500 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(pStart) >> 12;
501 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(pStart) + dwCount - 1) >> 12;
502 PVOID Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
503 SIZE_T Size = (LastPage - FirstPage + 1) * PAGE_SIZE;
504
505 /* Check validity of the VDD handle */
506 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
507 {
508 SetLastError(ERROR_INVALID_PARAMETER);
509 return FALSE;
510 }
511
512 if (dwCount == 0) return FALSE;
513
514 /* Commit the pages */
515 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
516 &Address,
517 0,
518 &Size,
519 MEM_COMMIT,
520 PAGE_READWRITE);
521 if (!NT_SUCCESS(Status)) return FALSE;
522
523 for (i = FirstPage; i <= LastPage; i++)
524 {
525 Hook = PageTable[i];
526 if (Hook == NULL) continue;
527
528 if (Hook->hVdd != hVdd)
529 {
530 DPRINT1("VDDDeInstallMemoryHook: Page %u owned by someone else.\n", i);
531 continue;
532 }
533
534 if (--Hook->Count == 0)
535 {
536 /* This hook has no more pages */
537 RemoveEntryList(&Hook->Entry);
538 RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
539 }
540
541 PageTable[i] = NULL;
542 }
543
544 return TRUE;
545 }
546
547 BOOL
548 WINAPI
549 VDDAllocMem(IN HANDLE hVdd,
550 IN PVOID Address,
551 IN ULONG Size)
552 {
553 NTSTATUS Status;
554 PMEM_HOOK Hook;
555 ULONG i;
556 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(Address) >> 12;
557 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(Address) + Size - 1) >> 12;
558 SIZE_T RealSize = (LastPage - FirstPage + 1) * PAGE_SIZE;
559
560 /* Check validity of the VDD handle */
561 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
562 {
563 SetLastError(ERROR_INVALID_PARAMETER);
564 return FALSE;
565 }
566
567 if (Size == 0) return FALSE;
568
569 /* Fixup the address */
570 Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
571
572 /* Be sure that all the region is held by the VDD */
573 for (i = FirstPage; i <= LastPage; i++)
574 {
575 Hook = PageTable[i];
576 if (Hook == NULL) return FALSE;
577
578 if (Hook->hVdd != hVdd)
579 {
580 DPRINT1("VDDAllocMem: Page %u owned by someone else.\n", i);
581 return FALSE;
582 }
583 }
584
585 /* OK, all the range is held by the VDD. Commit the pages. */
586 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
587 &Address,
588 0,
589 &RealSize,
590 MEM_COMMIT,
591 PAGE_READWRITE);
592 return NT_SUCCESS(Status);
593 }
594
595 BOOL
596 WINAPI
597 VDDFreeMem(IN HANDLE hVdd,
598 IN PVOID Address,
599 IN ULONG Size)
600 {
601 NTSTATUS Status;
602 PMEM_HOOK Hook;
603 ULONG i;
604 ULONG FirstPage = (ULONG_PTR)PHYS_TO_REAL(Address) >> 12;
605 ULONG LastPage = ((ULONG_PTR)PHYS_TO_REAL(Address) + Size - 1) >> 12;
606 SIZE_T RealSize = (LastPage - FirstPage + 1) * PAGE_SIZE;
607
608 /* Check validity of the VDD handle */
609 if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE)
610 {
611 SetLastError(ERROR_INVALID_PARAMETER);
612 return FALSE;
613 }
614
615 if (Size == 0) return FALSE;
616
617 /* Fixup the address */
618 Address = (PVOID)REAL_TO_PHYS(FirstPage * PAGE_SIZE);
619
620 /* Be sure that all the region is held by the VDD */
621 for (i = FirstPage; i <= LastPage; i++)
622 {
623 Hook = PageTable[i];
624 if (Hook == NULL) return FALSE;
625
626 if (Hook->hVdd != hVdd)
627 {
628 DPRINT1("VDDFreeMem: Page %u owned by someone else.\n", i);
629 return FALSE;
630 }
631 }
632
633 /* OK, all the range is held by the VDD. Decommit the pages. */
634 Status = NtFreeVirtualMemory(NtCurrentProcess(),
635 &Address,
636 &RealSize,
637 MEM_DECOMMIT);
638 return NT_SUCCESS(Status);
639 }
640
641 BOOL
642 WINAPI
643 VDDIncludeMem(IN HANDLE hVdd,
644 IN PVOID Address,
645 IN ULONG Size)
646 {
647 // FIXME
648 UNIMPLEMENTED;
649 return FALSE;
650 }
651
652 BOOL
653 WINAPI
654 VDDExcludeMem(IN HANDLE hVdd,
655 IN PVOID Address,
656 IN ULONG Size)
657 {
658 // FIXME
659 UNIMPLEMENTED;
660 return FALSE;
661 }
662
663
664
665 BOOLEAN
666 MemInitialize(VOID)
667 {
668 NTSTATUS Status;
669 SIZE_T MemorySize = MAX_ADDRESS; // See: kernel32/client/vdm.c!BaseGetVdmConfigInfo
670
671 InitializeListHead(&HookList);
672
673 #ifndef STANDALONE
674
675 /*
676 * The reserved region starts from the very first page.
677 * We need to commit the reserved first 16 MB virtual address.
678 *
679 * NOTE: NULL has another signification for NtAllocateVirtualMemory.
680 */
681 BaseAddress = (PVOID)1;
682
683 /*
684 * Since to get NULL, we allocated from 0x1, account for this.
685 * See also: kernel32/client/proc.c!CreateProcessInternalW
686 */
687 MemorySize -= 1;
688
689 #else
690
691 /* Allocate it anywhere */
692 BaseAddress = NULL;
693
694 #endif
695
696 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
697 &BaseAddress,
698 0,
699 &MemorySize,
700 #ifndef STANDALONE
701 MEM_COMMIT,
702 #else
703 MEM_RESERVE | MEM_COMMIT,
704 #endif
705 PAGE_EXECUTE_READWRITE);
706 if (!NT_SUCCESS(Status))
707 {
708 wprintf(L"FATAL: Failed to commit VDM memory, Status 0x%08lx\n", Status);
709 return FALSE;
710 }
711
712 #ifndef STANDALONE
713 ASSERT(BaseAddress == NULL);
714 #endif
715
716 /*
717 * For diagnostics purposes, we fill the memory with INT 0x03 codes
718 * so that if a program wants to execute random code in memory, we can
719 * retrieve the exact CS:IP where the problem happens.
720 */
721 RtlFillMemory(BaseAddress, MAX_ADDRESS, 0xCC);
722 return TRUE;
723 }
724
725 VOID
726 MemCleanup(VOID)
727 {
728 NTSTATUS Status;
729 SIZE_T MemorySize = MAX_ADDRESS;
730 PLIST_ENTRY Pointer;
731
732 while (!IsListEmpty(&HookList))
733 {
734 Pointer = RemoveHeadList(&HookList);
735 RtlFreeHeap(RtlGetProcessHeap(), 0, CONTAINING_RECORD(Pointer, MEM_HOOK, Entry));
736 }
737
738 /* Decommit the VDM memory */
739 Status = NtFreeVirtualMemory(NtCurrentProcess(),
740 &BaseAddress,
741 &MemorySize,
742 #ifndef STANDALONE
743 MEM_DECOMMIT
744 #else
745 MEM_RELEASE
746 #endif
747 );
748 if (!NT_SUCCESS(Status))
749 {
750 DPRINT1("NTVDM: Failed to decommit VDM memory, Status 0x%08lx\n", Status);
751 }
752 }
753
754 /* EOF */