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 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 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 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 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 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 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 275 VOID EmulatorSetA20(BOOLEAN Enabled) 276 { 277 A20Line = Enabled; 278 } 279 280 BOOLEAN EmulatorGetA20(VOID) 281 { 282 return A20Line; 283 } 284 285 VOID 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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