mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 06:55:55 +00:00
[NTVDM][FAST486]
- Implement VDDInstallMemoryHook and VDDDeInstallMemoryHook using page guards. - Implement another API for memory hooks that should be faster than page guards (for NTVDM only). - Adjust the VGA and EMS memory handlers to use this method. - In Fast486, implement a method that will allow us to "rewind" the current instruction, in case it was interrupted by a memory hook page fault. - Use a memory hook to protect the BIOS ROM from being written to. svn path=/trunk/; revision=66666
This commit is contained in:
parent
027720cd57
commit
888e1c450b
12 changed files with 668 additions and 233 deletions
|
@ -576,6 +576,10 @@ Fast486SetSegment
|
||||||
USHORT Selector
|
USHORT Selector
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
Fast486Rewind(PFAST486_STATE State);
|
||||||
|
|
||||||
#endif // _FAST486_H_
|
#endif // _FAST486_H_
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -333,4 +333,14 @@ Fast486SetSegment(PFAST486_STATE State,
|
||||||
Fast486LoadSegment(State, Segment, Selector);
|
Fast486LoadSegment(State, Segment, Selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
Fast486Rewind(PFAST486_STATE State)
|
||||||
|
{
|
||||||
|
/* This function is used when an instruction has been interrupted remotely */
|
||||||
|
State->PrefixFlags = 0;
|
||||||
|
State->InstPtr.Long = State->SavedInstPtr.Long;
|
||||||
|
State->PrefetchValid = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -37,6 +37,7 @@ list(APPEND SOURCE
|
||||||
emulator.c
|
emulator.c
|
||||||
int32.c
|
int32.c
|
||||||
io.c
|
io.c
|
||||||
|
memory.c
|
||||||
utils.c
|
utils.c
|
||||||
vddsup.c
|
vddsup.c
|
||||||
ntvdm.c
|
ntvdm.c
|
||||||
|
@ -45,6 +46,6 @@ list(APPEND SOURCE
|
||||||
|
|
||||||
add_executable(ntvdm ${SOURCE})
|
add_executable(ntvdm ${SOURCE})
|
||||||
set_module_type(ntvdm win32cui UNICODE IMAGEBASE 0x0F000000)
|
set_module_type(ntvdm win32cui UNICODE IMAGEBASE 0x0F000000)
|
||||||
target_link_libraries(ntvdm fast486)
|
target_link_libraries(ntvdm fast486 ${PSEH_LIB})
|
||||||
add_importlibs(ntvdm user32 gdi32 advapi32 msvcrt kernel32 ntdll)
|
add_importlibs(ntvdm user32 gdi32 advapi32 msvcrt kernel32 ntdll)
|
||||||
add_cd_file(TARGET ntvdm DESTINATION reactos/system32 FOR all)
|
add_cd_file(TARGET ntvdm DESTINATION reactos/system32 FOR all)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
|
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "cpu/callback.h"
|
#include "cpu/callback.h"
|
||||||
#include "cpu/bop.h"
|
#include "cpu/bop.h"
|
||||||
|
|
||||||
|
@ -40,6 +41,12 @@ PBIOS_CONFIG_TABLE Bct;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
static BOOLEAN NTAPI BiosRomWrite(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
/* Prevent writing to ROM */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
VOID WINAPI BiosEquipmentService(LPWORD Stack)
|
VOID WINAPI BiosEquipmentService(LPWORD Stack)
|
||||||
|
@ -74,6 +81,11 @@ BiosInitialize(IN LPCSTR BiosFileName)
|
||||||
// RegisterBop(BOP_EQUIPLIST , BiosEquipmentService);
|
// RegisterBop(BOP_EQUIPLIST , BiosEquipmentService);
|
||||||
// RegisterBop(BOP_GETMEMSIZE, BiosGetMemorySize);
|
// RegisterBop(BOP_GETMEMSIZE, BiosGetMemorySize);
|
||||||
|
|
||||||
|
MemInstallFastMemoryHook((PVOID)ROM_AREA_START,
|
||||||
|
ROM_AREA_END - ROM_AREA_START + 1,
|
||||||
|
NULL,
|
||||||
|
BiosRomWrite);
|
||||||
|
|
||||||
if (BiosFileName && BiosFileName[0] != '\0')
|
if (BiosFileName && BiosFileName[0] != '\0')
|
||||||
{
|
{
|
||||||
PVOID BiosLocation = NULL;
|
PVOID BiosLocation = NULL;
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "callback.h"
|
#include "callback.h"
|
||||||
#include "bop.h"
|
#include "bop.h"
|
||||||
#include <isvbop.h>
|
#include <isvbop.h>
|
||||||
|
#include <pseh/pseh2.h>
|
||||||
|
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "bios/rom.h"
|
#include "bios/rom.h"
|
||||||
|
@ -112,6 +114,8 @@ VOID CpuStep(VOID)
|
||||||
|
|
||||||
VOID CpuSimulate(VOID)
|
VOID CpuSimulate(VOID)
|
||||||
{
|
{
|
||||||
|
EXCEPTION_RECORD LocalExceptionRecord;
|
||||||
|
|
||||||
if (CpuCallLevel > MaxCpuCallLevel)
|
if (CpuCallLevel > MaxCpuCallLevel)
|
||||||
{
|
{
|
||||||
DisplayMessage(L"Too many CPU levels of recursion (%d, expected maximum %d)",
|
DisplayMessage(L"Too many CPU levels of recursion (%d, expected maximum %d)",
|
||||||
|
@ -125,7 +129,29 @@ VOID CpuSimulate(VOID)
|
||||||
DPRINT("CpuSimulate --> Level %d\n", CpuCallLevel);
|
DPRINT("CpuSimulate --> Level %d\n", CpuCallLevel);
|
||||||
|
|
||||||
CpuRunning = TRUE;
|
CpuRunning = TRUE;
|
||||||
while (VdmRunning && CpuRunning) ClockUpdate();
|
while (VdmRunning && CpuRunning)
|
||||||
|
{
|
||||||
|
_SEH2_TRY
|
||||||
|
{
|
||||||
|
while (VdmRunning && CpuRunning) ClockUpdate();
|
||||||
|
}
|
||||||
|
_SEH2_EXCEPT(LocalExceptionRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord,
|
||||||
|
EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
BOOLEAN Writing = (LocalExceptionRecord.ExceptionInformation[0] == 1);
|
||||||
|
DWORD FaultingAddress = (DWORD)LocalExceptionRecord.ExceptionInformation[1];
|
||||||
|
|
||||||
|
/* Make sure this was an access violation */
|
||||||
|
ASSERT(LocalExceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION);
|
||||||
|
|
||||||
|
/* Fix the CPU state */
|
||||||
|
Fast486Rewind(&EmulatorContext);
|
||||||
|
|
||||||
|
/* Call the handler */
|
||||||
|
MemExceptionHandler(FaultingAddress, Writing);
|
||||||
|
}
|
||||||
|
_SEH2_END;
|
||||||
|
}
|
||||||
|
|
||||||
DPRINT("CpuSimulate <-- Level %d\n", CpuCallLevel);
|
DPRINT("CpuSimulate <-- Level %d\n", CpuCallLevel);
|
||||||
CpuCallLevel--;
|
CpuCallLevel--;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <ndk/rtltypes.h>
|
#include <ndk/rtltypes.h>
|
||||||
#include <ndk/rtlfuncs.h>
|
#include <ndk/rtlfuncs.h>
|
||||||
#include "ems.h"
|
#include "ems.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
|
||||||
|
@ -294,23 +295,26 @@ static VOID WINAPI EmsIntHandler(LPWORD Stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VOID NTAPI EmsReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
// TODO: NOT IMPLEMENTED
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOLEAN NTAPI EmsWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
// TODO: NOT IMPLEMENTED
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
VOID EmsReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
|
||||||
{
|
|
||||||
// TODO: NOT IMPLEMENTED
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID EmsWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
|
||||||
{
|
|
||||||
// TODO: NOT IMPLEMENTED
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID EmsInitialize(VOID)
|
VOID EmsInitialize(VOID)
|
||||||
{
|
{
|
||||||
ULONG i;
|
ULONG i;
|
||||||
|
|
||||||
|
RtlZeroMemory(BitmapBuffer, sizeof(BitmapBuffer));
|
||||||
RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, EMS_TOTAL_PAGES);
|
RtlInitializeBitMap(&AllocBitmap, BitmapBuffer, EMS_TOTAL_PAGES);
|
||||||
|
|
||||||
for (i = 0; i < EMS_MAX_HANDLES; i++)
|
for (i = 0; i < EMS_MAX_HANDLES; i++)
|
||||||
|
@ -320,5 +324,16 @@ VOID EmsInitialize(VOID)
|
||||||
InitializeListHead(&HandleTable[i].PageList);
|
InitializeListHead(&HandleTable[i].PageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemInstallFastMemoryHook(SEG_OFF_TO_PTR(EMS_SEGMENT, 0),
|
||||||
|
EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE,
|
||||||
|
EmsReadMemory,
|
||||||
|
EmsWriteMemory);
|
||||||
|
|
||||||
RegisterBiosInt32(EMS_INTERRUPT_NUM, EmsIntHandler);
|
RegisterBiosInt32(EMS_INTERRUPT_NUM, EmsIntHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID EmsCleanup(VOID)
|
||||||
|
{
|
||||||
|
MemRemoveFastMemoryHook(SEG_OFF_TO_PTR(EMS_SEGMENT, 0),
|
||||||
|
EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
|
@ -12,15 +12,13 @@
|
||||||
/* DEFINITIONS ****************************************************************/
|
/* DEFINITIONS ****************************************************************/
|
||||||
|
|
||||||
#define EMS_INTERRUPT_NUM 0x67
|
#define EMS_INTERRUPT_NUM 0x67
|
||||||
#define EMS_SEGMENT 0xE000
|
#define EMS_SEGMENT 0xD000
|
||||||
#define EMS_MAX_HANDLES 16
|
#define EMS_MAX_HANDLES 16
|
||||||
#define EMS_TOTAL_PAGES 256
|
#define EMS_TOTAL_PAGES 256
|
||||||
#define EMS_PAGE_BITS 14
|
#define EMS_PAGE_BITS 14
|
||||||
#define EMS_PAGE_SIZE (1 << EMS_PAGE_BITS)
|
#define EMS_PAGE_SIZE (1 << EMS_PAGE_BITS)
|
||||||
#define EMS_ADDRESS 0xA00000
|
#define EMS_ADDRESS 0xA00000
|
||||||
#define EMS_PHYSICAL_PAGES 4
|
#define EMS_PHYSICAL_PAGES 4
|
||||||
#define EMS_START_ADDRESS (EMS_SEGMENT << 4)
|
|
||||||
#define EMS_END_ADDRESS (EMS_START_ADDRESS + EMS_PHYSICAL_PAGES * EMS_PAGE_SIZE)
|
|
||||||
|
|
||||||
#define EMS_STATUS_OK 0x00
|
#define EMS_STATUS_OK 0x00
|
||||||
#define EMS_STATUS_INTERNAL_ERROR 0x80
|
#define EMS_STATUS_INTERNAL_ERROR 0x80
|
||||||
|
@ -66,9 +64,8 @@ typedef struct _EMS_COPY_DATA
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
VOID EmsReadMemory(ULONG Address, PVOID Buffer, ULONG Size);
|
|
||||||
VOID EmsWriteMemory(ULONG Address, PVOID Buffer, ULONG Size);
|
|
||||||
VOID EmsInitialize(VOID);
|
VOID EmsInitialize(VOID);
|
||||||
|
VOID EmsCleanup(VOID);
|
||||||
|
|
||||||
#endif // _EMS_H_
|
#endif // _EMS_H_
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
|
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
#include "cpu/callback.h"
|
#include "cpu/callback.h"
|
||||||
#include "cpu/cpu.h"
|
#include "cpu/cpu.h"
|
||||||
|
@ -66,143 +67,35 @@ LPCWSTR ExceptionName[] =
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
static inline VOID
|
|
||||||
EmulatorMoveMemory(OUT VOID UNALIGNED *Destination,
|
|
||||||
IN const VOID UNALIGNED *Source,
|
|
||||||
IN SIZE_T Length)
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
/*
|
|
||||||
* We use a switch here to detect small moves of memory, as these
|
|
||||||
* constitute the bulk of our moves.
|
|
||||||
* Using RtlMoveMemory for all these small moves would be slow otherwise.
|
|
||||||
*/
|
|
||||||
switch (Length)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return;
|
|
||||||
|
|
||||||
case sizeof(UCHAR):
|
|
||||||
*(PUCHAR)Destination = *(PUCHAR)Source;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case sizeof(USHORT):
|
|
||||||
*(PUSHORT)Destination = *(PUSHORT)Source;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case sizeof(ULONG):
|
|
||||||
*(PULONG)Destination = *(PULONG)Source;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case sizeof(ULONGLONG):
|
|
||||||
*(PULONGLONG)Destination = *(PULONGLONG)Source;
|
|
||||||
return;
|
|
||||||
|
|
||||||
default:
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
__builtin_memmove(Destination, Source, Length);
|
|
||||||
#else
|
|
||||||
RtlMoveMemory(Destination, Source, Length);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // defined(_MSC_VER)
|
|
||||||
|
|
||||||
PUCHAR Dest = (PUCHAR)Destination;
|
|
||||||
PUCHAR Src = (PUCHAR)Source;
|
|
||||||
|
|
||||||
SIZE_T Count, NewSize = Length;
|
|
||||||
|
|
||||||
/* Move dword */
|
|
||||||
Count = NewSize >> 2; // NewSize / sizeof(ULONG);
|
|
||||||
NewSize = NewSize & 3; // NewSize % sizeof(ULONG);
|
|
||||||
__movsd(Dest, Src, Count);
|
|
||||||
Dest += Count << 2; // Count * sizeof(ULONG);
|
|
||||||
Src += Count << 2;
|
|
||||||
|
|
||||||
/* Move word */
|
|
||||||
Count = NewSize >> 1; // NewSize / sizeof(USHORT);
|
|
||||||
NewSize = NewSize & 1; // NewSize % sizeof(USHORT);
|
|
||||||
__movsw(Dest, Src, Count);
|
|
||||||
Dest += Count << 1; // Count * sizeof(USHORT);
|
|
||||||
Src += Count << 1;
|
|
||||||
|
|
||||||
/* Move byte */
|
|
||||||
Count = NewSize; // NewSize / sizeof(UCHAR);
|
|
||||||
// NewSize = NewSize; // NewSize % sizeof(UCHAR);
|
|
||||||
__movsb(Dest, Src, Count);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID WINAPI EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
VOID WINAPI EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(State);
|
UNREFERENCED_PARAMETER(State);
|
||||||
|
|
||||||
// BIG HACK!!!! To make BIOS images working correctly,
|
/* Mirror 0x000FFFF0 at 0xFFFFFFF0 */
|
||||||
// until Aleksander rewrites memory management!!
|
|
||||||
if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
|
if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
|
||||||
|
|
||||||
/* If the A20 line is disabled, mask bit 20 */
|
/* If the A20 line is disabled, mask bit 20 */
|
||||||
if (!A20Line) Address &= ~(1 << 20);
|
if (!A20Line) Address &= ~(1 << 20);
|
||||||
|
|
||||||
/* Make sure the requested address is valid */
|
if (Address >= MAX_ADDRESS) return;
|
||||||
if ((Address + Size) >= MAX_ADDRESS) return;
|
Size = min(Size, MAX_ADDRESS - Address);
|
||||||
|
|
||||||
/*
|
/* Read while calling fast memory hooks */
|
||||||
* Check if we are going to read the VGA memory and
|
MemRead(Address, Buffer, Size);
|
||||||
* copy it into the virtual address space if needed.
|
|
||||||
*/
|
|
||||||
if (((Address + Size) >= VgaGetVideoBaseAddress())
|
|
||||||
&& (Address < VgaGetVideoLimitAddress()))
|
|
||||||
{
|
|
||||||
DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
|
|
||||||
DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
|
|
||||||
- VgaAddress + 1;
|
|
||||||
LPBYTE DestBuffer = (LPBYTE)REAL_TO_PHYS(VgaAddress);
|
|
||||||
|
|
||||||
/* Read from the VGA memory */
|
|
||||||
VgaReadMemory(VgaAddress, DestBuffer, ActualSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the data from the virtual address space and store it in the buffer */
|
|
||||||
EmulatorMoveMemory(Buffer, REAL_TO_PHYS(Address), Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(State);
|
UNREFERENCED_PARAMETER(State);
|
||||||
|
|
||||||
// BIG HACK!!!! To make BIOS images working correctly,
|
|
||||||
// until Aleksander rewrites memory management!!
|
|
||||||
if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
|
|
||||||
|
|
||||||
/* If the A20 line is disabled, mask bit 20 */
|
/* If the A20 line is disabled, mask bit 20 */
|
||||||
if (!A20Line) Address &= ~(1 << 20);
|
if (!A20Line) Address &= ~(1 << 20);
|
||||||
|
|
||||||
/* Make sure the requested address is valid */
|
if (Address >= MAX_ADDRESS) return;
|
||||||
if ((Address + Size) >= MAX_ADDRESS) return;
|
Size = min(Size, MAX_ADDRESS - Address);
|
||||||
|
|
||||||
/* Make sure we don't write to the ROM area */
|
/* Write while calling fast memory hooks */
|
||||||
if ((Address + Size) >= ROM_AREA_START && (Address < ROM_AREA_END)) return;
|
MemWrite(Address, Buffer, Size);
|
||||||
|
|
||||||
/* Read the data from the buffer and store it in the virtual address space */
|
|
||||||
EmulatorMoveMemory(REAL_TO_PHYS(Address), Buffer, Size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if we modified the VGA memory.
|
|
||||||
*/
|
|
||||||
if (((Address + Size) >= VgaGetVideoBaseAddress())
|
|
||||||
&& (Address < VgaGetVideoLimitAddress()))
|
|
||||||
{
|
|
||||||
DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
|
|
||||||
DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
|
|
||||||
- VgaAddress + 1;
|
|
||||||
LPBYTE SrcBuffer = (LPBYTE)REAL_TO_PHYS(VgaAddress);
|
|
||||||
|
|
||||||
/* Write to the VGA memory */
|
|
||||||
VgaWriteMemory(VgaAddress, SrcBuffer, ActualSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
|
UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
|
||||||
|
@ -566,57 +459,13 @@ VOID DumpMemory(BOOLEAN TextFormat)
|
||||||
|
|
||||||
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
||||||
{
|
{
|
||||||
#ifdef STANDALONE
|
/* Initialize memory */
|
||||||
|
if (!MemInitialize())
|
||||||
/* Allocate 16 MB memory for the 16-bit address space */
|
|
||||||
BaseAddress = HeapAlloc(GetProcessHeap(), /*HEAP_ZERO_MEMORY*/ 0, MAX_ADDRESS);
|
|
||||||
if (BaseAddress == NULL)
|
|
||||||
{
|
{
|
||||||
wprintf(L"FATAL: Failed to allocate VDM memory.\n");
|
wprintf(L"Memory initialization failed.\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
NTSTATUS Status;
|
|
||||||
SIZE_T MemorySize = MAX_ADDRESS; // See: kernel32/client/vdm.c!BaseGetVdmConfigInfo
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The reserved region starts from the very first page.
|
|
||||||
* We need to commit the reserved first 16 MB virtual address.
|
|
||||||
*/
|
|
||||||
BaseAddress = (PVOID)1; // NULL has another signification for NtAllocateVirtualMemory
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since to get NULL, we allocated from 0x1, account for this.
|
|
||||||
* See also: kernel32/client/proc.c!CreateProcessInternalW
|
|
||||||
*/
|
|
||||||
MemorySize -= 1;
|
|
||||||
|
|
||||||
/* Commit the reserved memory */
|
|
||||||
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
||||||
&BaseAddress,
|
|
||||||
0,
|
|
||||||
&MemorySize,
|
|
||||||
MEM_COMMIT,
|
|
||||||
PAGE_EXECUTE_READWRITE);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
wprintf(L"FATAL: Failed to commit VDM memory, Status 0x%08lx\n", Status);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(BaseAddress == NULL);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For diagnostics purposes, we fill the memory with INT 0x03 codes
|
|
||||||
* so that if a program wants to execute random code in memory, we can
|
|
||||||
* retrieve the exact CS:IP where the problem happens.
|
|
||||||
*/
|
|
||||||
RtlFillMemory(BaseAddress, MAX_ADDRESS, 0xCC);
|
|
||||||
|
|
||||||
/* Initialize I/O ports */
|
/* Initialize I/O ports */
|
||||||
/* Initialize RAM */
|
/* Initialize RAM */
|
||||||
|
|
||||||
|
@ -700,11 +549,6 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
||||||
|
|
||||||
VOID EmulatorCleanup(VOID)
|
VOID EmulatorCleanup(VOID)
|
||||||
{
|
{
|
||||||
#ifndef STANDALONE
|
|
||||||
NTSTATUS Status;
|
|
||||||
SIZE_T MemorySize = MAX_ADDRESS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VgaCleanup();
|
VgaCleanup();
|
||||||
|
|
||||||
/* Close the input thread handle */
|
/* Close the input thread handle */
|
||||||
|
@ -713,6 +557,7 @@ VOID EmulatorCleanup(VOID)
|
||||||
|
|
||||||
PS2Cleanup();
|
PS2Cleanup();
|
||||||
|
|
||||||
|
EmsCleanup();
|
||||||
SpeakerCleanup();
|
SpeakerCleanup();
|
||||||
CmosCleanup();
|
CmosCleanup();
|
||||||
// PitCleanup();
|
// PitCleanup();
|
||||||
|
@ -721,29 +566,7 @@ VOID EmulatorCleanup(VOID)
|
||||||
// DmaCleanup();
|
// DmaCleanup();
|
||||||
|
|
||||||
CpuCleanup();
|
CpuCleanup();
|
||||||
|
MemCleanup();
|
||||||
#ifdef STANDALONE
|
|
||||||
|
|
||||||
/* Free the memory allocated for the 16-bit address space */
|
|
||||||
if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
/* The reserved region starts from the very first page */
|
|
||||||
// BaseAddress = (PVOID)1;
|
|
||||||
|
|
||||||
/* Since to get NULL, we allocated from 0x1, account for this */
|
|
||||||
MemorySize -= 1;
|
|
||||||
|
|
||||||
Status = NtFreeVirtualMemory(NtCurrentProcess(),
|
|
||||||
&BaseAddress,
|
|
||||||
&MemorySize,
|
|
||||||
MEM_DECOMMIT);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("NTVDM: Failed to decommit VDM memory, Status 0x%08lx\n", Status);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include <bios/vidbios.h>
|
#include <bios/vidbios.h>
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
/* PRIVATE VARIABLES **********************************************************/
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
@ -418,6 +419,16 @@ __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
|
||||||
static inline DWORD VgaGetAddressSize(VOID);
|
static inline DWORD VgaGetAddressSize(VOID);
|
||||||
static VOID VgaUpdateTextCursor(VOID);
|
static VOID VgaUpdateTextCursor(VOID);
|
||||||
|
|
||||||
|
static inline DWORD VgaGetVideoBaseAddress(VOID)
|
||||||
|
{
|
||||||
|
return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline DWORD VgaGetVideoLimitAddress(VOID)
|
||||||
|
{
|
||||||
|
return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
|
||||||
|
}
|
||||||
|
|
||||||
static VOID VgaUpdateCursorPosition(VOID)
|
static VOID VgaUpdateCursorPosition(VOID)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1745,16 +1756,6 @@ static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
DWORD VgaGetVideoBaseAddress(VOID)
|
|
||||||
{
|
|
||||||
return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD VgaGetVideoLimitAddress(VOID)
|
|
||||||
{
|
|
||||||
return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
|
|
||||||
}
|
|
||||||
|
|
||||||
COORD VgaGetDisplayResolution(VOID)
|
COORD VgaGetDisplayResolution(VOID)
|
||||||
{
|
{
|
||||||
COORD Resolution;
|
COORD Resolution;
|
||||||
|
@ -1881,12 +1882,15 @@ VOID VgaHorizontalRetrace(VOID)
|
||||||
InHorizontalRetrace = TRUE;
|
InHorizontalRetrace = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
|
VOID NTAPI VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
{
|
{
|
||||||
DWORD i;
|
DWORD i;
|
||||||
DWORD VideoAddress;
|
DWORD VideoAddress;
|
||||||
|
PUCHAR BufPtr = (PUCHAR)Buffer;
|
||||||
|
|
||||||
DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
|
DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
|
||||||
|
Address = max(min(Address, VgaGetVideoLimitAddress() - 1), VgaGetVideoBaseAddress());
|
||||||
|
Size = min(Size, VgaGetVideoLimitAddress() - Address + 1);
|
||||||
|
|
||||||
/* Ignore if video RAM access is disabled */
|
/* Ignore if video RAM access is disabled */
|
||||||
if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
|
if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
|
||||||
|
@ -1897,7 +1901,7 @@ VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
|
||||||
VideoAddress = VgaTranslateReadAddress(Address + i);
|
VideoAddress = VgaTranslateReadAddress(Address + i);
|
||||||
|
|
||||||
/* Copy the value to the buffer */
|
/* Copy the value to the buffer */
|
||||||
Buffer[i] = VgaMemory[VideoAddress];
|
BufPtr[i] = VgaMemory[VideoAddress];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load the latch registers */
|
/* Load the latch registers */
|
||||||
|
@ -1907,18 +1911,21 @@ VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
|
||||||
VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
|
VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
|
BOOLEAN NTAPI VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
{
|
{
|
||||||
DWORD i, j;
|
DWORD i, j;
|
||||||
DWORD VideoAddress;
|
DWORD VideoAddress;
|
||||||
|
PUCHAR BufPtr = (PUCHAR)Buffer;
|
||||||
|
|
||||||
DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
|
DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
|
||||||
|
Address = max(min(Address, VgaGetVideoLimitAddress() - 1), VgaGetVideoBaseAddress());
|
||||||
|
Size = min(Size, VgaGetVideoLimitAddress() - Address + 1);
|
||||||
|
|
||||||
/* Ignore if video RAM access is disabled */
|
/* Ignore if video RAM access is disabled */
|
||||||
if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
|
if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
|
||||||
|
|
||||||
/* Also ignore if write access to all planes is disabled */
|
/* Also ignore if write access to all planes is disabled */
|
||||||
if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
|
if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE;
|
||||||
|
|
||||||
/* Loop through each byte */
|
/* Loop through each byte */
|
||||||
for (i = 0; i < Size; i++)
|
for (i = 0; i < Size; i++)
|
||||||
|
@ -1951,9 +1958,11 @@ VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the value to the VGA memory */
|
/* Copy the value to the VGA memory */
|
||||||
VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
|
VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(BufPtr[i], j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID VgaClearMemory(VOID)
|
VOID VgaClearMemory(VOID)
|
||||||
|
@ -2074,6 +2083,9 @@ BOOLEAN VgaInitialize(HANDLE TextHandle)
|
||||||
|
|
||||||
/* Clear the VGA memory */
|
/* Clear the VGA memory */
|
||||||
VgaClearMemory();
|
VgaClearMemory();
|
||||||
|
|
||||||
|
/* Register the memory hook */
|
||||||
|
MemInstallFastMemoryHook((PVOID)0xA0000, 0x20000, VgaReadMemory, VgaWriteMemory);
|
||||||
|
|
||||||
/* Register the I/O Ports */
|
/* Register the I/O Ports */
|
||||||
RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
|
RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
|
||||||
|
@ -2112,6 +2124,7 @@ VOID VgaCleanup(VOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
VgaDetachFromConsole(FALSE);
|
VgaDetachFromConsole(FALSE);
|
||||||
|
MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
|
||||||
|
|
||||||
CloseHandle(AnotherEvent);
|
CloseHandle(AnotherEvent);
|
||||||
CloseHandle(EndEvent);
|
CloseHandle(EndEvent);
|
||||||
|
|
|
@ -258,14 +258,10 @@ VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent);
|
||||||
BOOL VgaAttachToConsole(VOID);
|
BOOL VgaAttachToConsole(VOID);
|
||||||
VOID VgaDetachFromConsole(BOOL ChangeMode);
|
VOID VgaDetachFromConsole(BOOL ChangeMode);
|
||||||
|
|
||||||
DWORD VgaGetVideoBaseAddress(VOID);
|
|
||||||
DWORD VgaGetVideoLimitAddress(VOID);
|
|
||||||
COORD VgaGetDisplayResolution(VOID);
|
COORD VgaGetDisplayResolution(VOID);
|
||||||
VOID VgaRefreshDisplay(VOID);
|
VOID VgaRefreshDisplay(VOID);
|
||||||
VOID VgaHorizontalRetrace(VOID);
|
VOID VgaHorizontalRetrace(VOID);
|
||||||
VOID VgaWriteFont(UINT FontNumber, CONST UCHAR *FontData, UINT Height);
|
VOID VgaWriteFont(UINT FontNumber, CONST UCHAR *FontData, UINT Height);
|
||||||
VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size);
|
|
||||||
VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size);
|
|
||||||
VOID VgaClearMemory(VOID);
|
VOID VgaClearMemory(VOID);
|
||||||
|
|
||||||
BOOLEAN VgaInitialize(HANDLE TextHandle);
|
BOOLEAN VgaInitialize(HANDLE TextHandle);
|
||||||
|
|
422
reactos/subsystems/mvdm/ntvdm/memory.c
Normal file
422
reactos/subsystems/mvdm/ntvdm/memory.c
Normal file
|
@ -0,0 +1,422 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Virtual DOS Machine
|
||||||
|
* FILE: memory.c
|
||||||
|
* PURPOSE: Expanded Memory Support
|
||||||
|
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *******************************************************************/
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
|
||||||
|
#include "emulator.h"
|
||||||
|
#include <ndk/mmfuncs.h>
|
||||||
|
#include <ndk/rtlfuncs.h>
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
/* PRIVATE VARIABLES **********************************************************/
|
||||||
|
|
||||||
|
static LIST_ENTRY HookList;
|
||||||
|
static PMEM_HOOK PageTable[TOTAL_PAGES];
|
||||||
|
|
||||||
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
static inline VOID
|
||||||
|
MemFastMoveMemory(OUT VOID UNALIGNED *Destination,
|
||||||
|
IN const VOID UNALIGNED *Source,
|
||||||
|
IN SIZE_T Length)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
/*
|
||||||
|
* We use a switch here to detect small moves of memory, as these
|
||||||
|
* constitute the bulk of our moves.
|
||||||
|
* Using RtlMoveMemory for all these small moves would be slow otherwise.
|
||||||
|
*/
|
||||||
|
switch (Length)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case sizeof(UCHAR):
|
||||||
|
*(PUCHAR)Destination = *(PUCHAR)Source;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case sizeof(USHORT):
|
||||||
|
*(PUSHORT)Destination = *(PUSHORT)Source;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case sizeof(ULONG):
|
||||||
|
*(PULONG)Destination = *(PULONG)Source;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case sizeof(ULONGLONG):
|
||||||
|
*(PULONGLONG)Destination = *(PULONGLONG)Source;
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__builtin_memmove(Destination, Source, Length);
|
||||||
|
#else
|
||||||
|
RtlMoveMemory(Destination, Source, Length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // defined(_MSC_VER)
|
||||||
|
|
||||||
|
PUCHAR Dest = (PUCHAR)Destination;
|
||||||
|
PUCHAR Src = (PUCHAR)Source;
|
||||||
|
|
||||||
|
SIZE_T Count, NewSize = Length;
|
||||||
|
|
||||||
|
/* Move dword */
|
||||||
|
Count = NewSize >> 2; // NewSize / sizeof(ULONG);
|
||||||
|
NewSize = NewSize & 3; // NewSize % sizeof(ULONG);
|
||||||
|
__movsd(Dest, Src, Count);
|
||||||
|
Dest += Count << 2; // Count * sizeof(ULONG);
|
||||||
|
Src += Count << 2;
|
||||||
|
|
||||||
|
/* Move word */
|
||||||
|
Count = NewSize >> 1; // NewSize / sizeof(USHORT);
|
||||||
|
NewSize = NewSize & 1; // NewSize % sizeof(USHORT);
|
||||||
|
__movsw(Dest, Src, Count);
|
||||||
|
Dest += Count << 1; // Count * sizeof(USHORT);
|
||||||
|
Src += Count << 1;
|
||||||
|
|
||||||
|
/* Move byte */
|
||||||
|
Count = NewSize; // NewSize / sizeof(UCHAR);
|
||||||
|
// NewSize = NewSize; // NewSize % sizeof(UCHAR);
|
||||||
|
__movsb(Dest, Src, Count);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
VOID
|
||||||
|
ReadPage(PMEM_HOOK Hook, ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
if (Hook && !Hook->hVdd && Hook->FastReadHandler)
|
||||||
|
{
|
||||||
|
Hook->FastReadHandler(Address, REAL_TO_PHYS(Address), Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemFastMoveMemory(Buffer, REAL_TO_PHYS(Address), Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
VOID
|
||||||
|
WritePage(PMEM_HOOK Hook, ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
if (!Hook
|
||||||
|
|| Hook->hVdd
|
||||||
|
|| !Hook->FastWriteHandler
|
||||||
|
|| Hook->FastWriteHandler(Address, Buffer, Size))
|
||||||
|
{
|
||||||
|
MemFastMoveMemory(REAL_TO_PHYS(Address), Buffer, Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
|
VOID
|
||||||
|
MemRead(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
ULONG i, Offset, Length;
|
||||||
|
ULONG FirstPage = Address >> 12;
|
||||||
|
ULONG LastPage = (Address + Size - 1) >> 12;
|
||||||
|
|
||||||
|
MemFastMoveMemory(Buffer, REAL_TO_PHYS(Address), Size);
|
||||||
|
|
||||||
|
if (FirstPage == LastPage)
|
||||||
|
{
|
||||||
|
ReadPage(PageTable[FirstPage], Address, Buffer, Size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = FirstPage; i <= LastPage; i++)
|
||||||
|
{
|
||||||
|
Offset = (i == FirstPage) ? (Address & (PAGE_SIZE - 1)) : 0;
|
||||||
|
Length = ((i == LastPage) ? (Address + Size - (LastPage << 12)) : PAGE_SIZE) - Offset;
|
||||||
|
|
||||||
|
ReadPage(PageTable[i], (i << 12) + Offset, Buffer, Length);
|
||||||
|
Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
MemWrite(ULONG Address, PVOID Buffer, ULONG Size)
|
||||||
|
{
|
||||||
|
ULONG i, Offset, Length;
|
||||||
|
ULONG FirstPage = Address >> 12;
|
||||||
|
ULONG LastPage = (Address + Size - 1) >> 12;
|
||||||
|
|
||||||
|
if (FirstPage == LastPage)
|
||||||
|
{
|
||||||
|
WritePage(PageTable[FirstPage], Address, Buffer, Size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = FirstPage; i <= LastPage; i++)
|
||||||
|
{
|
||||||
|
Offset = (i == FirstPage) ? (Address & (PAGE_SIZE - 1)) : 0;
|
||||||
|
Length = ((i == LastPage) ? (Address + Size - (LastPage << 12)) : PAGE_SIZE) - Offset;
|
||||||
|
|
||||||
|
WritePage(PageTable[i], (i << 12) + Offset, Buffer, Length);
|
||||||
|
Buffer = (PVOID)((ULONG_PTR)Buffer + Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
MemExceptionHandler(DWORD Address, BOOLEAN Writing)
|
||||||
|
{
|
||||||
|
PMEM_HOOK Hook = PageTable[Address >> 12];
|
||||||
|
DPRINT("The memory at 0x%08X could not be %s.\n", Address, Writing ? "written" : "read");
|
||||||
|
|
||||||
|
/* Exceptions are only supposed to happen when using VDD-style memory hooks */
|
||||||
|
ASSERT(Address < MAX_ADDRESS && Hook != NULL && Hook->hVdd != NULL);
|
||||||
|
|
||||||
|
/* Call the VDD handler */
|
||||||
|
Hook->VddHandler(Address, Writing);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
MemInstallFastMemoryHook(PVOID Address,
|
||||||
|
ULONG Size,
|
||||||
|
PMEMORY_READ_HANDLER ReadHandler,
|
||||||
|
PMEMORY_WRITE_HANDLER WriteHandler)
|
||||||
|
{
|
||||||
|
PMEM_HOOK Hook;
|
||||||
|
ULONG i;
|
||||||
|
ULONG FirstPage = (ULONG)Address >> 12;
|
||||||
|
ULONG LastPage = ((ULONG)Address + Size - 1) >> 12;
|
||||||
|
|
||||||
|
/* Make sure none of these pages are already allocated */
|
||||||
|
for (i = FirstPage; i <= LastPage; i++)
|
||||||
|
{
|
||||||
|
if (PageTable[i] != NULL) return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(MEM_HOOK));
|
||||||
|
if (Hook == NULL) return FALSE;
|
||||||
|
|
||||||
|
Hook->hVdd = NULL;
|
||||||
|
Hook->Count = LastPage - FirstPage + 1;
|
||||||
|
Hook->FastReadHandler = ReadHandler;
|
||||||
|
Hook->FastWriteHandler = WriteHandler;
|
||||||
|
|
||||||
|
for (i = FirstPage; i <= LastPage; i++) PageTable[i] = Hook;
|
||||||
|
|
||||||
|
InsertTailList(&HookList, &Hook->Entry);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
MemRemoveFastMemoryHook(PVOID Address, ULONG Size)
|
||||||
|
{
|
||||||
|
ULONG i;
|
||||||
|
ULONG FirstPage = (ULONG)Address >> 12;
|
||||||
|
ULONG LastPage = ((ULONG)Address + Size - 1) >> 12;
|
||||||
|
|
||||||
|
if (Size == 0) return FALSE;
|
||||||
|
|
||||||
|
for (i = FirstPage; i <= LastPage; i++)
|
||||||
|
{
|
||||||
|
PMEM_HOOK Hook = PageTable[i];
|
||||||
|
if (Hook == NULL || Hook->hVdd != NULL) continue;
|
||||||
|
|
||||||
|
if (--Hook->Count == 0)
|
||||||
|
{
|
||||||
|
/* This hook has no more pages */
|
||||||
|
RemoveEntryList(&Hook->Entry);
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
WINAPI
|
||||||
|
VDDInstallMemoryHook(HANDLE hVdd,
|
||||||
|
PVOID pStart,
|
||||||
|
DWORD dwCount,
|
||||||
|
PVDD_MEMORY_HANDLER pHandler)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
PMEM_HOOK Hook;
|
||||||
|
ULONG i;
|
||||||
|
ULONG FirstPage = (ULONG)pStart >> 12;
|
||||||
|
ULONG LastPage = ((ULONG)pStart + dwCount - 1) >> 12;
|
||||||
|
PVOID Address = (PVOID)(FirstPage * PAGE_SIZE);
|
||||||
|
SIZE_T Size = (LastPage - FirstPage + 1) * PAGE_SIZE;
|
||||||
|
|
||||||
|
/* Check validity of the VDD handle */
|
||||||
|
if (hVdd == NULL || hVdd == INVALID_HANDLE_VALUE) return FALSE;
|
||||||
|
if (dwCount == 0) return FALSE;
|
||||||
|
|
||||||
|
/* Make sure none of these pages are already allocated */
|
||||||
|
for (i = FirstPage; i <= LastPage; i++)
|
||||||
|
{
|
||||||
|
if (PageTable[i] != NULL) return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hook = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(MEM_HOOK));
|
||||||
|
if (Hook == NULL) return FALSE;
|
||||||
|
|
||||||
|
Hook->hVdd = hVdd;
|
||||||
|
Hook->Count = LastPage - FirstPage + 1;
|
||||||
|
Hook->VddHandler = pHandler;
|
||||||
|
|
||||||
|
/* Decommit the pages */
|
||||||
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &Address, &Size, MEM_DECOMMIT);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = FirstPage; i <= LastPage; i++) PageTable[i] = Hook;
|
||||||
|
|
||||||
|
InsertTailList(&HookList, &Hook->Entry);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
WINAPI
|
||||||
|
VDDDeInstallMemoryHook(HANDLE hVdd,
|
||||||
|
PVOID pStart,
|
||||||
|
DWORD dwCount)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG i;
|
||||||
|
ULONG FirstPage = (ULONG)pStart >> 12;
|
||||||
|
ULONG LastPage = ((ULONG)pStart + dwCount - 1) >> 12;
|
||||||
|
PVOID Address = (PVOID)(FirstPage * PAGE_SIZE);
|
||||||
|
SIZE_T Size = (LastPage - FirstPage + 1) * PAGE_SIZE;
|
||||||
|
|
||||||
|
if (dwCount == 0) return FALSE;
|
||||||
|
|
||||||
|
/* Commit the pages */
|
||||||
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
||||||
|
&Address,
|
||||||
|
0,
|
||||||
|
&Size,
|
||||||
|
MEM_COMMIT,
|
||||||
|
PAGE_READWRITE);
|
||||||
|
if (!NT_SUCCESS(Status)) return FALSE;
|
||||||
|
|
||||||
|
for (i = FirstPage; i <= LastPage; i++)
|
||||||
|
{
|
||||||
|
PMEM_HOOK Hook = PageTable[i];
|
||||||
|
if (Hook == NULL) continue;
|
||||||
|
|
||||||
|
if (Hook->hVdd != hVdd)
|
||||||
|
{
|
||||||
|
DPRINT1("VDDDeInstallMemoryHook: Page %u owned by someone else.\n", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--Hook->Count == 0)
|
||||||
|
{
|
||||||
|
/* This hook has no more pages */
|
||||||
|
RemoveEntryList(&Hook->Entry);
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, Hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTable[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
MemInitialize(VOID)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
SIZE_T MemorySize = MAX_ADDRESS; // See: kernel32/client/vdm.c!BaseGetVdmConfigInfo
|
||||||
|
|
||||||
|
#ifndef STANDALONE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The reserved region starts from the very first page.
|
||||||
|
* We need to commit the reserved first 16 MB virtual address.
|
||||||
|
*/
|
||||||
|
BaseAddress = (PVOID)1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since to get NULL, we allocated from 0x1, account for this.
|
||||||
|
* See also: kernel32/client/proc.c!CreateProcessInternalW
|
||||||
|
*/
|
||||||
|
MemorySize -= 1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Allocate it anywhere */
|
||||||
|
BaseAddress = NULL;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
||||||
|
&BaseAddress,
|
||||||
|
0,
|
||||||
|
&MemorySize,
|
||||||
|
#ifndef STANDALONE
|
||||||
|
MEM_COMMIT,
|
||||||
|
#else
|
||||||
|
MEM_RESERVE | MEM_COMMIT,
|
||||||
|
#endif
|
||||||
|
PAGE_EXECUTE_READWRITE);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
wprintf(L"FATAL: Failed to commit VDM memory, Status 0x%08lx\n", Status);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef STANDALONE
|
||||||
|
ASSERT(BaseAddress == NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InitializeListHead(&HookList);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For diagnostics purposes, we fill the memory with INT 0x03 codes
|
||||||
|
* so that if a program wants to execute random code in memory, we can
|
||||||
|
* retrieve the exact CS:IP where the problem happens.
|
||||||
|
*/
|
||||||
|
RtlFillMemory(BaseAddress, MAX_ADDRESS, 0xCC);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
MemCleanup(VOID)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
SIZE_T MemorySize = MAX_ADDRESS;
|
||||||
|
|
||||||
|
while (HookList.Flink != &HookList)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY Pointer = RemoveHeadList(&HookList);
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, CONTAINING_RECORD(Pointer, MEM_HOOK, Entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decommit the VDM memory */
|
||||||
|
Status = NtFreeVirtualMemory(NtCurrentProcess(),
|
||||||
|
&BaseAddress,
|
||||||
|
&MemorySize,
|
||||||
|
#ifndef STANDALONE
|
||||||
|
MEM_DECOMMIT
|
||||||
|
#else
|
||||||
|
MEM_RELEASE
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("NTVDM: Failed to decommit VDM memory, Status 0x%08lx\n", Status);
|
||||||
|
}
|
||||||
|
}
|
116
reactos/subsystems/mvdm/ntvdm/memory.h
Normal file
116
reactos/subsystems/mvdm/ntvdm/memory.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: GPLv2+ - See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Virtual DOS Machine
|
||||||
|
* FILE: memory.h
|
||||||
|
* PURPOSE: Expanded Memory Support
|
||||||
|
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MEMORY_H_
|
||||||
|
#define _MEMORY_H_
|
||||||
|
|
||||||
|
/* DEFINITIONS ****************************************************************/
|
||||||
|
|
||||||
|
#define TOTAL_PAGES (MAX_ADDRESS / PAGE_SIZE)
|
||||||
|
|
||||||
|
typedef VOID
|
||||||
|
(WINAPI *PVDD_MEMORY_HANDLER)
|
||||||
|
(
|
||||||
|
DWORD FaultingAddress,
|
||||||
|
BOOLEAN Writing
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef VOID
|
||||||
|
(WINAPI *PMEMORY_READ_HANDLER)
|
||||||
|
(
|
||||||
|
ULONG Address,
|
||||||
|
PVOID Buffer,
|
||||||
|
ULONG Size
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef BOOLEAN
|
||||||
|
(WINAPI *PMEMORY_WRITE_HANDLER)
|
||||||
|
(
|
||||||
|
ULONG Address,
|
||||||
|
PVOID Buffer,
|
||||||
|
ULONG Size
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct _MEM_HOOK
|
||||||
|
{
|
||||||
|
LIST_ENTRY Entry;
|
||||||
|
HANDLE hVdd;
|
||||||
|
ULONG Count;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PVDD_MEMORY_HANDLER VddHandler;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
PMEMORY_READ_HANDLER FastReadHandler;
|
||||||
|
PMEMORY_WRITE_HANDLER FastWriteHandler;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} MEM_HOOK, *PMEM_HOOK;
|
||||||
|
|
||||||
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
BOOLEAN MemInitialize(VOID);
|
||||||
|
VOID MemCleanup(VOID);
|
||||||
|
VOID MemExceptionHandler(DWORD Address, BOOLEAN Writing);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
MemRead
|
||||||
|
(
|
||||||
|
ULONG Address,
|
||||||
|
PVOID Buffer,
|
||||||
|
ULONG Size
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
MemWrite
|
||||||
|
(
|
||||||
|
ULONG Address,
|
||||||
|
PVOID Buffer,
|
||||||
|
ULONG Size
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
MemInstallFastMemoryHook
|
||||||
|
(
|
||||||
|
PVOID Address,
|
||||||
|
ULONG Size,
|
||||||
|
PMEMORY_READ_HANDLER ReadHandler,
|
||||||
|
PMEMORY_WRITE_HANDLER WriteHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
MemRemoveFastMemoryHook
|
||||||
|
(
|
||||||
|
PVOID Address,
|
||||||
|
ULONG Size
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
WINAPI
|
||||||
|
VDDInstallMemoryHook
|
||||||
|
(
|
||||||
|
HANDLE hVdd,
|
||||||
|
PVOID pStart,
|
||||||
|
DWORD dwCount,
|
||||||
|
PVDD_MEMORY_HANDLER pHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
WINAPI
|
||||||
|
VDDDeInstallMemoryHook
|
||||||
|
(
|
||||||
|
HANDLE hVdd,
|
||||||
|
PVOID pStart,
|
||||||
|
DWORD dwCount
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // _MEMORY_H_
|
||||||
|
|
||||||
|
/* EOF */
|
Loading…
Add table
Add a link
Reference in a new issue