mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-03 04:13:31 +00:00
[BRANCHES]
Merge the NTVDM branch back to trunk. New/changed components are: ntvdm, fast486, basesrv, ntdll, kernel32 and csrsrv. svn path=/trunk/; revision=63177
This commit is contained in:
@@ -56,7 +56,8 @@ add_compile_flags("/wd4290")
|
||||
# - C4163: 'identifier': not available as an intrinsic function
|
||||
# - C4229: modifiers on data are ignored
|
||||
# - C4700: uninitialized variable usage
|
||||
add_compile_flags("/we4013 /we4020 /we4022 /we4047 /we4098 /we4113 /we4129 /we4163 /we4229 /we4700")
|
||||
# - C4603: macro is not defined or definition is different after precompiled header use
|
||||
add_compile_flags("/we4013 /we4020 /we4022 /we4047 /we4098 /we4113 /we4129 /we4163 /we4229 /we4700 /we4603")
|
||||
|
||||
# Enable warnings above the default level, but don't treat them as errors:
|
||||
# - C4115: named type definition in parentheses
|
||||
|
||||
@@ -101,6 +101,9 @@ CsrAllocateCaptureBuffer(IN ULONG ArgumentCount,
|
||||
/* Align it to a 4-byte boundary */
|
||||
BufferSize = (BufferSize + 3) & ~3;
|
||||
|
||||
/* Add the size of the alignment padding for each argument */
|
||||
BufferSize += ArgumentCount * 3;
|
||||
|
||||
/* Allocate memory from the port heap */
|
||||
CaptureBuffer = RtlAllocateHeap(CsrPortHeap, HEAP_ZERO_MEMORY, BufferSize);
|
||||
if (CaptureBuffer == NULL) return NULL;
|
||||
|
||||
@@ -2301,7 +2301,7 @@ CreateProcessInternalW(IN HANDLE hUserToken,
|
||||
BOOLEAN InJob, SaferNeeded, UseLargePages, HavePrivilege;
|
||||
BOOLEAN QuerySection, SkipSaferAndAppCompat;
|
||||
CONTEXT Context;
|
||||
BASE_API_MESSAGE CsrMsg;
|
||||
BASE_API_MESSAGE CsrMsg[2];
|
||||
PBASE_CREATE_PROCESS CreateProcessMsg;
|
||||
PCSR_CAPTURE_BUFFER CaptureBuffer;
|
||||
PVOID BaseAddress, PrivilegeState, RealTimePrivilegeState;
|
||||
@@ -2431,8 +2431,8 @@ CreateProcessInternalW(IN HANDLE hUserToken,
|
||||
IsWowApp = FALSE;
|
||||
|
||||
/* Set message structures */
|
||||
CreateProcessMsg = &CsrMsg.Data.CreateProcessRequest;
|
||||
CheckVdmMsg = &CsrMsg.Data.CheckVDMRequest;
|
||||
CreateProcessMsg = &CsrMsg[0].Data.CreateProcessRequest;
|
||||
CheckVdmMsg = &CsrMsg[1].Data.CheckVDMRequest;
|
||||
|
||||
/* Clear the more complex structures by zeroing out their entire memory */
|
||||
RtlZeroMemory(&Context, sizeof(Context));
|
||||
@@ -3197,7 +3197,7 @@ StartScan:
|
||||
/* Pick which kind of WOW mode we want to run in */
|
||||
VdmBinaryType = (dwCreationFlags &
|
||||
CREATE_SEPARATE_WOW_VDM) ?
|
||||
BINARY_TYPE_WOW : BINARY_TYPE_SEPARATE_WOW;
|
||||
BINARY_TYPE_SEPARATE_WOW : BINARY_TYPE_WOW;
|
||||
|
||||
/* Get all the VDM settings and current status */
|
||||
Status = BaseCheckVDM(VdmBinaryType,
|
||||
@@ -3205,7 +3205,7 @@ StartScan:
|
||||
lpCommandLine,
|
||||
lpCurrentDirectory,
|
||||
&VdmAnsiEnv,
|
||||
&CsrMsg,
|
||||
&CsrMsg[1],
|
||||
&VdmTask,
|
||||
dwCreationFlags,
|
||||
&StartupInfo,
|
||||
@@ -3342,7 +3342,7 @@ StartScan:
|
||||
lpCommandLine,
|
||||
lpCurrentDirectory,
|
||||
&VdmAnsiEnv,
|
||||
&CsrMsg,
|
||||
&CsrMsg[1],
|
||||
&VdmTask,
|
||||
dwCreationFlags,
|
||||
&StartupInfo,
|
||||
@@ -3966,6 +3966,8 @@ StartScan:
|
||||
&VdmWaitObject,
|
||||
VdmTask,
|
||||
VdmBinaryType);
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
/* Bail out on failure */
|
||||
DPRINT1("Failed to update VDM with wait object\n");
|
||||
@@ -4335,7 +4337,7 @@ StartScan:
|
||||
}
|
||||
|
||||
/* We are finally ready to call CSRSS to tell it about our new process! */
|
||||
CsrClientCallServer((PCSR_API_MESSAGE)&CsrMsg,
|
||||
CsrClientCallServer((PCSR_API_MESSAGE)&CsrMsg[0],
|
||||
CaptureBuffer,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
|
||||
BasepCreateProcess),
|
||||
@@ -4349,12 +4351,12 @@ StartScan:
|
||||
}
|
||||
|
||||
/* Check if CSRSS failed to accept ownership of the new Windows process */
|
||||
if (!NT_SUCCESS(CsrMsg.Status))
|
||||
if (!NT_SUCCESS(CsrMsg[0].Status))
|
||||
{
|
||||
/* Terminate the process and enter failure path with the CSRSS status */
|
||||
DPRINT1("Failed to tell csrss about new process\n");
|
||||
BaseSetLastNTError(CsrMsg.Status);
|
||||
NtTerminateProcess(ProcessHandle, CsrMsg.Status);
|
||||
BaseSetLastNTError(CsrMsg[0].Status);
|
||||
NtTerminateProcess(ProcessHandle, CsrMsg[0].Status);
|
||||
Result = FALSE;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ BaseIsDosApplication(IN PUNICODE_STRING PathName,
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL
|
||||
NTSTATUS
|
||||
WINAPI
|
||||
BaseCheckVDM(IN ULONG BinaryType,
|
||||
IN PCWCH ApplicationName,
|
||||
@@ -77,9 +77,354 @@ BaseCheckVDM(IN ULONG BinaryType,
|
||||
IN LPSTARTUPINFOW StartupInfo,
|
||||
IN HANDLE hUserToken OPTIONAL)
|
||||
{
|
||||
/* This is not supported */
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
NTSTATUS Status;
|
||||
PBASE_CHECK_VDM CheckVdm = &ApiMessage->Data.CheckVDMRequest;
|
||||
PCSR_CAPTURE_BUFFER CaptureBuffer;
|
||||
PWCHAR CurrentDir = NULL;
|
||||
PWCHAR ShortAppName = NULL;
|
||||
PWCHAR ShortCurrentDir = NULL;
|
||||
ULONG Length;
|
||||
PCHAR AnsiCmdLine = NULL;
|
||||
PCHAR AnsiAppName = NULL;
|
||||
PCHAR AnsiCurDirectory = NULL;
|
||||
PCHAR AnsiDesktop = NULL;
|
||||
PCHAR AnsiTitle = NULL;
|
||||
PCHAR AnsiReserved = NULL;
|
||||
STARTUPINFOA AnsiStartupInfo;
|
||||
ULONG NumStrings = 5;
|
||||
|
||||
if (CurrentDirectory == NULL)
|
||||
{
|
||||
/* Allocate memory for the current directory path */
|
||||
Length = GetCurrentDirectoryW(0, NULL);
|
||||
CurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
Length * sizeof(WCHAR));
|
||||
if (CurrentDir == NULL)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Get the current directory */
|
||||
GetCurrentDirectoryW(Length, CurrentDir);
|
||||
CurrentDirectory = CurrentDir;
|
||||
}
|
||||
|
||||
/* Calculate the size of the short application name */
|
||||
Length = GetShortPathNameW(ApplicationName, NULL, 0);
|
||||
|
||||
/* Allocate memory for the short application name */
|
||||
ShortAppName = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
Length * sizeof(WCHAR));
|
||||
if (!ShortAppName)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Get the short application name */
|
||||
if (!GetShortPathNameW(ApplicationName, ShortAppName, Length))
|
||||
{
|
||||
/* Try to determine which error occurred */
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
{
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Status = STATUS_OBJECT_PATH_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Calculate the size of the short current directory path */
|
||||
Length = GetShortPathNameW(CurrentDirectory, NULL, 0);
|
||||
|
||||
/* Allocate memory for the short current directory path */
|
||||
ShortCurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
Length * sizeof(WCHAR));
|
||||
if (!ShortCurrentDir)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Get the short current directory path */
|
||||
if (!GetShortPathNameW(CurrentDirectory, ShortCurrentDir, Length))
|
||||
{
|
||||
/* Try to determine which error occurred */
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
{
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Status = STATUS_OBJECT_PATH_INVALID;
|
||||
}
|
||||
}
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Setup the input parameters */
|
||||
CheckVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
|
||||
CheckVdm->BinaryType = BinaryType;
|
||||
CheckVdm->CodePage = CP_ACP;
|
||||
CheckVdm->dwCreationFlags = CreationFlags;
|
||||
CheckVdm->CurDrive = CurrentDirectory[0] - L'A';
|
||||
CheckVdm->CmdLen = wcslen(CommandLine) + 1;
|
||||
CheckVdm->AppLen = wcslen(ShortAppName) + 1;
|
||||
CheckVdm->PifLen = 0; // TODO: PIF file support!
|
||||
CheckVdm->CurDirectoryLen = wcslen(ShortCurrentDir) + 1;
|
||||
CheckVdm->EnvLen = AnsiEnvironment->Length;
|
||||
CheckVdm->DesktopLen = (StartupInfo->lpDesktop != NULL) ? (wcslen(StartupInfo->lpDesktop) + 1) : 0;
|
||||
CheckVdm->TitleLen = (StartupInfo->lpTitle != NULL) ? (wcslen(StartupInfo->lpTitle) + 1) : 0;
|
||||
CheckVdm->ReservedLen = (StartupInfo->lpReserved != NULL) ? (wcslen(StartupInfo->lpReserved) + 1) : 0;
|
||||
|
||||
if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
|
||||
{
|
||||
/* Set the standard handles */
|
||||
CheckVdm->StdIn = StartupInfo->hStdInput;
|
||||
CheckVdm->StdOut = StartupInfo->hStdOutput;
|
||||
CheckVdm->StdErr = StartupInfo->hStdError;
|
||||
}
|
||||
|
||||
/* Allocate memory for the ANSI strings */
|
||||
AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen);
|
||||
AnsiAppName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->AppLen);
|
||||
AnsiCurDirectory = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CurDirectoryLen);
|
||||
if (StartupInfo->lpDesktop) AnsiDesktop = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
CheckVdm->DesktopLen);
|
||||
if (StartupInfo->lpTitle) AnsiTitle = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
CheckVdm->TitleLen);
|
||||
if (StartupInfo->lpReserved) AnsiReserved = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
CheckVdm->ReservedLen);
|
||||
|
||||
if (!AnsiCmdLine
|
||||
|| !AnsiAppName
|
||||
|| !AnsiCurDirectory
|
||||
|| (StartupInfo->lpDesktop && !AnsiDesktop)
|
||||
|| (StartupInfo->lpTitle && !AnsiTitle)
|
||||
|| (StartupInfo->lpReserved && !AnsiReserved))
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Convert the command line into an ANSI string */
|
||||
WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
CommandLine,
|
||||
CheckVdm->CmdLen,
|
||||
AnsiCmdLine,
|
||||
CheckVdm->CmdLen,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Convert the short application name into an ANSI string */
|
||||
WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
ShortAppName,
|
||||
CheckVdm->AppLen,
|
||||
AnsiAppName,
|
||||
CheckVdm->AppLen,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Convert the short current directory path into an ANSI string */
|
||||
WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
ShortCurrentDir,
|
||||
CheckVdm->CurDirectoryLen,
|
||||
AnsiCurDirectory,
|
||||
CheckVdm->CurDirectoryLen,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (StartupInfo->lpDesktop)
|
||||
{
|
||||
/* Convert the desktop name into an ANSI string */
|
||||
WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
StartupInfo->lpDesktop,
|
||||
CheckVdm->DesktopLen,
|
||||
AnsiDesktop,
|
||||
CheckVdm->DesktopLen,
|
||||
NULL,
|
||||
NULL);
|
||||
NumStrings++;
|
||||
}
|
||||
|
||||
if (StartupInfo->lpTitle)
|
||||
{
|
||||
/* Convert the title into an ANSI string */
|
||||
WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
StartupInfo->lpTitle,
|
||||
CheckVdm->TitleLen,
|
||||
AnsiTitle,
|
||||
CheckVdm->TitleLen,
|
||||
NULL,
|
||||
NULL);
|
||||
NumStrings++;
|
||||
}
|
||||
|
||||
if (StartupInfo->lpReserved)
|
||||
{
|
||||
/* Convert the reserved value into an ANSI string */
|
||||
WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
StartupInfo->lpReserved,
|
||||
CheckVdm->ReservedLen,
|
||||
AnsiReserved,
|
||||
CheckVdm->ReservedLen,
|
||||
NULL,
|
||||
NULL);
|
||||
NumStrings++;
|
||||
}
|
||||
|
||||
/* Fill the ANSI startup info structure */
|
||||
RtlCopyMemory(&AnsiStartupInfo, StartupInfo, sizeof(STARTUPINFO));
|
||||
AnsiStartupInfo.lpReserved = AnsiReserved;
|
||||
AnsiStartupInfo.lpDesktop = AnsiDesktop;
|
||||
AnsiStartupInfo.lpTitle = AnsiTitle;
|
||||
|
||||
/* Allocate the capture buffer */
|
||||
CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings,
|
||||
CheckVdm->CmdLen
|
||||
+ CheckVdm->AppLen
|
||||
+ CheckVdm->PifLen
|
||||
+ CheckVdm->CurDirectoryLen
|
||||
+ CheckVdm->DesktopLen
|
||||
+ CheckVdm->TitleLen
|
||||
+ CheckVdm->ReservedLen
|
||||
+ CheckVdm->EnvLen
|
||||
+ sizeof(STARTUPINFOA));
|
||||
if (CaptureBuffer == NULL)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Capture the command line */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
AnsiCmdLine,
|
||||
CheckVdm->CmdLen,
|
||||
(PVOID*)&CheckVdm->CmdLine);
|
||||
|
||||
/* Capture the application name */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
AnsiAppName,
|
||||
CheckVdm->AppLen,
|
||||
(PVOID*)&CheckVdm->AppName);
|
||||
|
||||
CheckVdm->PifFile = NULL; // TODO: PIF file support!
|
||||
|
||||
/* Capture the current directory */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
AnsiCurDirectory,
|
||||
CheckVdm->CurDirectoryLen,
|
||||
(PVOID*)&CheckVdm->CurDirectory);
|
||||
|
||||
/* Capture the environment */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
AnsiEnvironment->Buffer,
|
||||
CheckVdm->EnvLen,
|
||||
(PVOID*)&CheckVdm->Env);
|
||||
|
||||
/* Capture the startup info structure */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
&AnsiStartupInfo,
|
||||
sizeof(STARTUPINFOA),
|
||||
(PVOID*)&CheckVdm->StartupInfo);
|
||||
|
||||
if (StartupInfo->lpDesktop)
|
||||
{
|
||||
/* Capture the desktop name */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
AnsiDesktop,
|
||||
CheckVdm->DesktopLen,
|
||||
(PVOID*)&CheckVdm->Desktop);
|
||||
}
|
||||
else CheckVdm->Desktop = NULL;
|
||||
|
||||
if (StartupInfo->lpTitle)
|
||||
{
|
||||
/* Capture the title */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
AnsiTitle,
|
||||
CheckVdm->TitleLen,
|
||||
(PVOID*)&CheckVdm->Title);
|
||||
}
|
||||
else CheckVdm->Title = NULL;
|
||||
|
||||
if (StartupInfo->lpReserved)
|
||||
{
|
||||
/* Capture the reserved parameter */
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
AnsiReserved,
|
||||
CheckVdm->ReservedLen,
|
||||
(PVOID*)&CheckVdm->Reserved);
|
||||
}
|
||||
else CheckVdm->Reserved = NULL;
|
||||
|
||||
/* Send the message to CSRSS */
|
||||
Status = CsrClientCallServer((PCSR_API_MESSAGE)ApiMessage,
|
||||
CaptureBuffer,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCheckVDM),
|
||||
sizeof(BASE_CHECK_VDM));
|
||||
|
||||
/* Write back the task ID */
|
||||
*iTask = CheckVdm->iTask;
|
||||
|
||||
Cleanup:
|
||||
|
||||
/* Free the ANSI strings */
|
||||
if (AnsiCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCmdLine);
|
||||
if (AnsiAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiAppName);
|
||||
if (AnsiCurDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCurDirectory);
|
||||
if (AnsiDesktop) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiDesktop);
|
||||
if (AnsiTitle) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiTitle);
|
||||
if (AnsiReserved) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiReserved);
|
||||
|
||||
/* Free the capture buffer */
|
||||
CsrFreeCaptureBuffer(CaptureBuffer);
|
||||
|
||||
/* Free the short paths */
|
||||
if (ShortAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName);
|
||||
if (ShortCurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir);
|
||||
|
||||
/* Free the current directory, if it was allocated here */
|
||||
if (CurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
BOOL
|
||||
@@ -89,10 +434,9 @@ BaseUpdateVDMEntry(IN ULONG UpdateIndex,
|
||||
IN ULONG IndexInfo,
|
||||
IN ULONG BinaryType)
|
||||
{
|
||||
#if 0 // Unimplemented in BASESRV
|
||||
NTSTATUS Status;
|
||||
BASE_API_MESSAGE ApiMessage;
|
||||
PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVdmEntry;
|
||||
PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVDMEntryRequest;
|
||||
|
||||
/* Check what update is being sent */
|
||||
switch (UpdateIndex)
|
||||
@@ -155,7 +499,7 @@ BaseUpdateVDMEntry(IN ULONG UpdateIndex,
|
||||
/* Return it to the caller */
|
||||
*WaitHandle = UpdateVdmEntry->WaitObjectForParent;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We made it */
|
||||
return TRUE;
|
||||
}
|
||||
@@ -165,11 +509,10 @@ WINAPI
|
||||
BaseCheckForVDM(IN HANDLE ProcessHandle,
|
||||
OUT LPDWORD ExitCode)
|
||||
{
|
||||
#if 0 // Unimplemented in BASESRV
|
||||
NTSTATUS Status;
|
||||
EVENT_BASIC_INFORMATION EventBasicInfo;
|
||||
BASE_API_MESSAGE ApiMessage;
|
||||
PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVdmExitCode;
|
||||
PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVDMExitCodeRequest;
|
||||
|
||||
/* It's VDM if the process is actually a wait handle (an event) */
|
||||
Status = NtQueryEvent(ProcessHandle,
|
||||
@@ -192,7 +535,6 @@ BaseCheckForVDM(IN HANDLE ProcessHandle,
|
||||
|
||||
/* Get the exit code from the reply */
|
||||
*ExitCode = GetVdmExitCode->ExitCode;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -335,7 +677,7 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
|
||||
if (!lpEnvironment)
|
||||
{
|
||||
/* Nope, create one */
|
||||
Status = RtlCreateEnvironment(TRUE, (PWCHAR*)&Environment);
|
||||
Status = RtlCreateEnvironment(TRUE, &Environment);
|
||||
if (!NT_SUCCESS(Status)) goto Quickie;
|
||||
}
|
||||
else
|
||||
@@ -376,6 +718,7 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
|
||||
p = NewEnvironment;
|
||||
|
||||
/* FIXME: Code here */
|
||||
DPRINT1("BaseCreateVDMEnvironment is half-plemented!\n");
|
||||
|
||||
/* Terminate it */
|
||||
*p++ = UNICODE_NULL;
|
||||
@@ -574,7 +917,7 @@ InternalGetBinaryType(HANDLE hFile)
|
||||
return BINARY_PE_EXE32;
|
||||
}
|
||||
|
||||
if(!memcmp(magic, "NE", 1))
|
||||
if(!memcmp(magic, "NE", 2))
|
||||
{
|
||||
/* This is a Windows executable (NE) header. This can
|
||||
* mean either a 16-bit OS/2 or a 16-bit Windows or even a
|
||||
@@ -755,46 +1098,399 @@ CmdBatNotification (
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*/
|
||||
DWORD
|
||||
VOID
|
||||
WINAPI
|
||||
ExitVDM (
|
||||
DWORD Unknown0,
|
||||
DWORD Unknown1
|
||||
)
|
||||
ExitVDM(BOOL IsWow, ULONG iWowTask)
|
||||
{
|
||||
STUB;
|
||||
return 0;
|
||||
BASE_API_MESSAGE ApiMessage;
|
||||
PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest;
|
||||
|
||||
/* Setup the input parameters */
|
||||
ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
|
||||
ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */
|
||||
ExitVdm->WaitObjectForVDM = NULL;
|
||||
|
||||
/* Call CSRSS */
|
||||
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
NULL,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM),
|
||||
sizeof(BASE_EXIT_VDM));
|
||||
|
||||
/* Close the returned wait object handle, if any */
|
||||
if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL))
|
||||
{
|
||||
CloseHandle(ExitVdm->WaitObjectForVDM);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
BOOL
|
||||
WINAPI
|
||||
GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
BOOL Result = FALSE;
|
||||
BASE_API_MESSAGE ApiMessage;
|
||||
PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest;
|
||||
PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest;
|
||||
PBASE_SET_REENTER_COUNT SetReenterCount = &ApiMessage.Data.SetReenterCountRequest;
|
||||
PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
|
||||
ULONG NumStrings = 0;
|
||||
|
||||
if (CommandData != NULL)
|
||||
{
|
||||
if (CommandData->VDMState & (VDM_NOT_LOADED | VDM_NOT_READY | VDM_READY))
|
||||
{
|
||||
/* Clear the structure */
|
||||
ZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
|
||||
|
||||
/* Setup the input parameters */
|
||||
GetNextVdmCommand->iTask = CommandData->TaskId;
|
||||
GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
|
||||
GetNextVdmCommand->CmdLen = CommandData->CmdLen;
|
||||
GetNextVdmCommand->AppLen = CommandData->AppLen;
|
||||
GetNextVdmCommand->PifLen = CommandData->PifLen;
|
||||
GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
|
||||
GetNextVdmCommand->EnvLen = CommandData->EnvLen;
|
||||
GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
|
||||
GetNextVdmCommand->TitleLen = CommandData->TitleLen;
|
||||
GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
|
||||
GetNextVdmCommand->VDMState = CommandData->VDMState;
|
||||
|
||||
/* Count the number of strings */
|
||||
if (CommandData->CmdLen) NumStrings++;
|
||||
if (CommandData->AppLen) NumStrings++;
|
||||
if (CommandData->PifLen) NumStrings++;
|
||||
if (CommandData->CurDirectoryLen) NumStrings++;
|
||||
if (CommandData->EnvLen) NumStrings++;
|
||||
if (CommandData->DesktopLen) NumStrings++;
|
||||
if (CommandData->TitleLen) NumStrings++;
|
||||
if (CommandData->ReservedLen) NumStrings++;
|
||||
|
||||
/* Allocate the capture buffer */
|
||||
CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
|
||||
GetNextVdmCommand->CmdLen
|
||||
+ GetNextVdmCommand->AppLen
|
||||
+ GetNextVdmCommand->PifLen
|
||||
+ GetNextVdmCommand->CurDirectoryLen
|
||||
+ GetNextVdmCommand->EnvLen
|
||||
+ GetNextVdmCommand->DesktopLen
|
||||
+ GetNextVdmCommand->TitleLen
|
||||
+ GetNextVdmCommand->ReservedLen
|
||||
+ sizeof(STARTUPINFOA));
|
||||
if (CaptureBuffer == NULL)
|
||||
{
|
||||
BaseSetLastNTError(STATUS_NO_MEMORY);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Allocate memory for the startup info */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
sizeof(STARTUPINFOA),
|
||||
(PVOID*)&GetNextVdmCommand->StartupInfo);
|
||||
|
||||
if (CommandData->CmdLen)
|
||||
{
|
||||
/* Allocate memory for the command line */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->CmdLen,
|
||||
(PVOID*)&GetNextVdmCommand->CmdLine);
|
||||
}
|
||||
|
||||
if (CommandData->AppLen)
|
||||
{
|
||||
/* Allocate memory for the application name */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->AppLen,
|
||||
(PVOID*)&GetNextVdmCommand->AppName);
|
||||
}
|
||||
|
||||
if (CommandData->PifLen)
|
||||
{
|
||||
/* Allocate memory for the PIF file name */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->PifLen,
|
||||
(PVOID*)&GetNextVdmCommand->PifFile);
|
||||
}
|
||||
|
||||
if (CommandData->CurDirectoryLen)
|
||||
{
|
||||
/* Allocate memory for the current directory */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->CurDirectoryLen,
|
||||
(PVOID*)&GetNextVdmCommand->CurDirectory);
|
||||
}
|
||||
|
||||
if (CommandData->EnvLen)
|
||||
{
|
||||
/* Allocate memory for the environment */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->EnvLen,
|
||||
(PVOID*)&GetNextVdmCommand->Env);
|
||||
}
|
||||
|
||||
if (CommandData->DesktopLen)
|
||||
{
|
||||
/* Allocate memory for the desktop name */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->DesktopLen,
|
||||
(PVOID*)&GetNextVdmCommand->Desktop);
|
||||
}
|
||||
|
||||
if (CommandData->TitleLen)
|
||||
{
|
||||
/* Allocate memory for the title */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->TitleLen,
|
||||
(PVOID*)&GetNextVdmCommand->Title);
|
||||
}
|
||||
|
||||
if (CommandData->ReservedLen)
|
||||
{
|
||||
/* Allocate memory for the reserved parameter */
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
CommandData->ReservedLen,
|
||||
(PVOID*)&GetNextVdmCommand->Reserved);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* Call CSRSS */
|
||||
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
CaptureBuffer,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
|
||||
sizeof(BASE_GET_NEXT_VDM_COMMAND));
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
BaseSetLastNTError(Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Did we receive an event handle? */
|
||||
if (GetNextVdmCommand->WaitObjectForVDM != NULL)
|
||||
{
|
||||
/* Wait for the event to become signaled and try again */
|
||||
Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
|
||||
FALSE,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
BaseSetLastNTError(Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Set the retry flag and clear the exit code */
|
||||
GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
|
||||
GetNextVdmCommand->ExitCode = 0;
|
||||
}
|
||||
}
|
||||
while (GetNextVdmCommand->WaitObjectForVDM != NULL);
|
||||
|
||||
/* Write back the standard handles */
|
||||
CommandData->StdIn = GetNextVdmCommand->StdIn;
|
||||
CommandData->StdOut = GetNextVdmCommand->StdOut;
|
||||
CommandData->StdErr = GetNextVdmCommand->StdErr;
|
||||
|
||||
/* Write back the startup info */
|
||||
RtlMoveMemory(&CommandData->StartupInfo,
|
||||
GetNextVdmCommand->StartupInfo,
|
||||
sizeof(STARTUPINFOA));
|
||||
|
||||
if (CommandData->CmdLen)
|
||||
{
|
||||
/* Write back the command line */
|
||||
RtlMoveMemory(CommandData->CmdLine,
|
||||
GetNextVdmCommand->CmdLine,
|
||||
GetNextVdmCommand->CmdLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->CmdLen = GetNextVdmCommand->CmdLen;
|
||||
}
|
||||
|
||||
if (CommandData->AppLen)
|
||||
{
|
||||
/* Write back the application name */
|
||||
RtlMoveMemory(CommandData->AppName,
|
||||
GetNextVdmCommand->AppName,
|
||||
GetNextVdmCommand->AppLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->AppLen = GetNextVdmCommand->AppLen;
|
||||
}
|
||||
|
||||
if (CommandData->PifLen)
|
||||
{
|
||||
/* Write back the PIF file name */
|
||||
RtlMoveMemory(CommandData->PifFile,
|
||||
GetNextVdmCommand->PifFile,
|
||||
GetNextVdmCommand->PifLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->PifLen = GetNextVdmCommand->PifLen;
|
||||
}
|
||||
|
||||
if (CommandData->CurDirectoryLen)
|
||||
{
|
||||
/* Write back the current directory */
|
||||
RtlMoveMemory(CommandData->CurDirectory,
|
||||
GetNextVdmCommand->CurDirectory,
|
||||
GetNextVdmCommand->CurDirectoryLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
|
||||
}
|
||||
|
||||
if (CommandData->EnvLen)
|
||||
{
|
||||
/* Write back the environment */
|
||||
RtlMoveMemory(CommandData->Env,
|
||||
GetNextVdmCommand->Env,
|
||||
GetNextVdmCommand->EnvLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->EnvLen = GetNextVdmCommand->EnvLen;
|
||||
}
|
||||
|
||||
if (CommandData->DesktopLen)
|
||||
{
|
||||
/* Write back the desktop name */
|
||||
RtlMoveMemory(CommandData->Desktop,
|
||||
GetNextVdmCommand->Desktop,
|
||||
GetNextVdmCommand->DesktopLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
|
||||
}
|
||||
|
||||
if (CommandData->TitleLen)
|
||||
{
|
||||
/* Write back the title */
|
||||
RtlMoveMemory(CommandData->Title,
|
||||
GetNextVdmCommand->Title,
|
||||
GetNextVdmCommand->TitleLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->TitleLen = GetNextVdmCommand->TitleLen;
|
||||
}
|
||||
|
||||
if (CommandData->ReservedLen)
|
||||
{
|
||||
/* Write back the reserved parameter */
|
||||
RtlMoveMemory(CommandData->Reserved,
|
||||
GetNextVdmCommand->Reserved,
|
||||
GetNextVdmCommand->ReservedLen);
|
||||
|
||||
/* Set the actual length */
|
||||
CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
|
||||
}
|
||||
|
||||
/* Write the remaining output parameters */
|
||||
CommandData->TaskId = GetNextVdmCommand->iTask;
|
||||
CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
|
||||
CommandData->CodePage = GetNextVdmCommand->CodePage;
|
||||
CommandData->ExitCode = GetNextVdmCommand->ExitCode;
|
||||
CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
|
||||
CommandData->VDMState = GetNextVdmCommand->VDMState;
|
||||
CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
|
||||
|
||||
/* It was successful */
|
||||
Result = TRUE;
|
||||
}
|
||||
else if ((CommandData->VDMState == VDM_INC_REENTER_COUNT)
|
||||
|| (CommandData->VDMState == VDM_DEC_REENTER_COUNT))
|
||||
{
|
||||
/* Setup the input parameters */
|
||||
SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
|
||||
SetReenterCount->fIncDec = CommandData->VDMState;
|
||||
|
||||
/* Call CSRSS */
|
||||
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
NULL,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
|
||||
sizeof(BASE_SET_REENTER_COUNT));
|
||||
BaseSetLastNTError(Status);
|
||||
Result = NT_SUCCESS(Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||||
Result = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Call CSRSS */
|
||||
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
NULL,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
|
||||
sizeof(BASE_IS_FIRST_VDM));
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
BaseSetLastNTError(Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Return TRUE if this is the first VDM */
|
||||
Result = IsFirstVdm->FirstVDM;
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*/
|
||||
DWORD
|
||||
WINAPI
|
||||
GetNextVDMCommand (
|
||||
DWORD Unknown0
|
||||
)
|
||||
GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
|
||||
{
|
||||
STUB;
|
||||
return 0;
|
||||
}
|
||||
BASE_API_MESSAGE ApiMessage;
|
||||
PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
|
||||
PCSR_CAPTURE_BUFFER CaptureBuffer;
|
||||
|
||||
/* Allocate the capture buffer */
|
||||
CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
|
||||
if (CaptureBuffer == NULL)
|
||||
{
|
||||
BaseSetLastNTError(STATUS_NO_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
DWORD
|
||||
WINAPI
|
||||
GetVDMCurrentDirectories (
|
||||
DWORD Unknown0,
|
||||
DWORD Unknown1
|
||||
)
|
||||
{
|
||||
STUB;
|
||||
return 0;
|
||||
/* Setup the input parameters */
|
||||
VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
|
||||
CsrAllocateMessagePointer(CaptureBuffer,
|
||||
cchCurDirs,
|
||||
(PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
|
||||
|
||||
/* Call CSRSS */
|
||||
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
CaptureBuffer,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs),
|
||||
sizeof(BASE_GETSET_VDM_CURDIRS));
|
||||
|
||||
/* Set the last error */
|
||||
BaseSetLastNTError(ApiMessage.Status);
|
||||
|
||||
if (NT_SUCCESS(ApiMessage.Status))
|
||||
{
|
||||
/* Copy the result */
|
||||
RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs);
|
||||
}
|
||||
|
||||
/* Free the capture buffer */
|
||||
CsrFreeCaptureBuffer(CaptureBuffer);
|
||||
|
||||
/* Return the size if it was successful, or if the buffer was too small */
|
||||
return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL))
|
||||
? VDMCurrentDirsRequest->cchCurDirs : 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -851,17 +1547,44 @@ RegisterWowExec (
|
||||
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*/
|
||||
BOOL
|
||||
WINAPI
|
||||
SetVDMCurrentDirectories (
|
||||
DWORD Unknown0,
|
||||
DWORD Unknown1
|
||||
)
|
||||
SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
|
||||
{
|
||||
STUB;
|
||||
return FALSE;
|
||||
BASE_API_MESSAGE ApiMessage;
|
||||
PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
|
||||
PCSR_CAPTURE_BUFFER CaptureBuffer;
|
||||
|
||||
/* Allocate the capture buffer */
|
||||
CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
|
||||
if (CaptureBuffer == NULL)
|
||||
{
|
||||
BaseSetLastNTError(STATUS_NO_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Setup the input parameters */
|
||||
VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
|
||||
CsrCaptureMessageBuffer(CaptureBuffer,
|
||||
lpszzCurDirs,
|
||||
cchCurDirs,
|
||||
(PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
|
||||
|
||||
/* Call CSRSS */
|
||||
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
CaptureBuffer,
|
||||
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs),
|
||||
sizeof(BASE_GETSET_VDM_CURDIRS));
|
||||
|
||||
/* Free the capture buffer */
|
||||
CsrFreeCaptureBuffer(CaptureBuffer);
|
||||
|
||||
/* Set the last error */
|
||||
BaseSetLastNTError(ApiMessage.Status);
|
||||
|
||||
return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -882,12 +1605,15 @@ VDMConsoleOperation (
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
DWORD
|
||||
BOOL
|
||||
WINAPI
|
||||
VDMOperationStarted (
|
||||
DWORD Unknown0
|
||||
)
|
||||
VDMOperationStarted(IN ULONG Unknown0)
|
||||
{
|
||||
STUB;
|
||||
return 0;
|
||||
DPRINT1("VDMOperationStarted(%d)\n", Unknown0);
|
||||
|
||||
return
|
||||
BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler,
|
||||
NULL,
|
||||
0,
|
||||
Unknown0);
|
||||
}
|
||||
|
||||
@@ -8,42 +8,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/* CONSTANTS ******************************************************************/
|
||||
|
||||
typedef enum _VDM_ENTRY_CODE
|
||||
{
|
||||
VdmEntryUndo,
|
||||
VdmEntryUpdateProcess,
|
||||
VdmEntryUpdateControlCHandler
|
||||
} VDM_ENTRY_CODE;
|
||||
|
||||
//
|
||||
// Undo States
|
||||
//
|
||||
#define VDM_UNDO_PARTIAL 0x01
|
||||
#define VDM_UNDO_FULL 0x02
|
||||
#define VDM_UNDO_REUSE 0x04
|
||||
#define VDM_UNDO_COMPLETED 0x08
|
||||
|
||||
//
|
||||
// Binary Types to share with VDM
|
||||
//
|
||||
#define BINARY_TYPE_EXE 0x01
|
||||
#define BINARY_TYPE_COM 0x02
|
||||
#define BINARY_TYPE_PIF 0x03
|
||||
#define BINARY_TYPE_DOS 0x10
|
||||
#define BINARY_TYPE_SEPARATE_WOW 0x20
|
||||
#define BINARY_TYPE_WOW 0x40
|
||||
#define BINARY_TYPE_WOW_EX 0x80
|
||||
|
||||
//
|
||||
// VDM States
|
||||
//
|
||||
#define VDM_NOT_LOADED 0x01
|
||||
#define VDM_NOT_READY 0x02
|
||||
#define VDM_READY 0x04
|
||||
|
||||
|
||||
/* FUNCTION PROTOTYPES ********************************************************/
|
||||
|
||||
BOOL
|
||||
@@ -87,7 +51,7 @@ BaseCheckForVDM(
|
||||
OUT LPDWORD ExitCode
|
||||
);
|
||||
|
||||
BOOL
|
||||
NTSTATUS
|
||||
WINAPI
|
||||
BaseCheckVDM(
|
||||
IN ULONG BinaryType,
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <win/basemsg.h>
|
||||
#include <win/console.h>
|
||||
#include <win/conmsg.h>
|
||||
#include <win/vdm.h>
|
||||
|
||||
/* DDK Driver Headers */
|
||||
#include <mountmgr.h>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* isvbop.h
|
||||
*
|
||||
* Windows NT Device Driver Kit
|
||||
*
|
||||
* This file is part of the ReactOS DDK package.
|
||||
*
|
||||
* Contributors:
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*
|
||||
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
*
|
||||
* This source code is offered for use in the public domain. You may
|
||||
* use, modify or distribute it freely.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but
|
||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||
* DISCLAIMED. This includes but is not limited to warranties of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The corresponding ASM header of this file is isvbop.inc.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define BOP_3RDPARTY 0x58 // 3rd-party VDD BOP
|
||||
#define BOP_UNSIMULATE 0xFE // Stop execution
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
||||
#define RegisterModule() __asm__(".byte 0xC4, 0xC4, %c0, 0" : : "i"(BOP_3RDPARTY))
|
||||
#define UnRegisterModule() __asm__(".byte 0xC4, 0xC4, %c0, 1" : : "i"(BOP_3RDPARTY))
|
||||
#define DispatchCall() __asm__(".byte 0xC4, 0xC4, %c0, 2" : : "i"(BOP_3RDPARTY))
|
||||
#define VDDUnSimulate16() __asm__(".byte 0xC4, 0xC4, %c0" : : "i"(BOP_UNSIMULATE))
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#define RegisterModule() _asm _emit 0xC4 _asm _emit 0xC4 _asm _emit BOP_3RDPARTY _asm _emit 0
|
||||
#define UnRegisterModule() _asm _emit 0xC4 _asm _emit 0xC4 _asm _emit BOP_3RDPARTY _asm _emit 1
|
||||
#define DispatchCall() _asm _emit 0xC4 _asm _emit 0xC4 _asm _emit BOP_3RDPARTY _asm _emit 2
|
||||
#define VDDUnSimulate16() _asm _emit 0xC4 _asm _emit 0xC4 _asm _emit BOP_UNSIMULATE
|
||||
|
||||
#else
|
||||
#error Unknown compiler for inline assembler
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* isvbop.inc
|
||||
*
|
||||
* Windows NT Device Driver Kit
|
||||
*
|
||||
* This file is part of the ReactOS DDK package.
|
||||
*
|
||||
* Contributors:
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*
|
||||
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
*
|
||||
* This source code is offered for use in the public domain. You may
|
||||
* use, modify or distribute it freely.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but
|
||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||
* DISCLAIMED. This includes but is not limited to warranties of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the corresponding ASM header for isvbop.h.
|
||||
* Please refer to isvbop.h for information about these interfaces.
|
||||
*/
|
||||
|
||||
#include <asm.inc>
|
||||
|
||||
BOP_3RDPARTY = HEX(58)
|
||||
BOP_UNSIMULATE = HEX(FE)
|
||||
|
||||
MACRO(RegisterModule)
|
||||
.byte HEX(C4), HEX(C4), BOP_3RDPARTY, 0
|
||||
ENDM
|
||||
|
||||
MACRO(UnRegisterModule)
|
||||
.byte HEX(C4), HEX(C4), BOP_3RDPARTY, 1
|
||||
ENDM
|
||||
|
||||
MACRO(DispatchCall)
|
||||
.byte HEX(C4), HEX(C4), BOP_3RDPARTY, 2
|
||||
ENDM
|
||||
|
||||
MACRO(VDDUnSimulate16)
|
||||
.byte HEX(C4), HEX(C4), BOP_UNSIMULATE
|
||||
ENDM
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* nt_vdd.h
|
||||
*
|
||||
* Windows NT Device Driver Kit
|
||||
*
|
||||
* This file is part of the ReactOS DDK package.
|
||||
*
|
||||
* Contributors:
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*
|
||||
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
*
|
||||
* This source code is offered for use in the public domain. You may
|
||||
* use, modify or distribute it freely.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but
|
||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||
* DISCLAIMED. This includes but is not limited to warranties of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _NT_VDD
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* VDM Control
|
||||
*/
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDSimulate16(VOID);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDTerminateVDM(VOID);
|
||||
|
||||
|
||||
/*
|
||||
* I/O Port services
|
||||
*/
|
||||
|
||||
typedef VOID (*PFNVDD_INB) (WORD iport, PBYTE data);
|
||||
typedef VOID (*PFNVDD_INW) (WORD iport, PWORD data);
|
||||
typedef VOID (*PFNVDD_INSB) (WORD iport, PBYTE data, WORD count);
|
||||
typedef VOID (*PFNVDD_INSW) (WORD iport, PWORD data, WORD count);
|
||||
typedef VOID (*PFNVDD_OUTB) (WORD iport, BYTE data);
|
||||
typedef VOID (*PFNVDD_OUTW) (WORD iport, WORD data);
|
||||
typedef VOID (*PFNVDD_OUTSB) (WORD iport, PBYTE data, WORD count);
|
||||
typedef VOID (*PFNVDD_OUTSW) (WORD iport, PWORD data, WORD count);
|
||||
|
||||
typedef struct _VDD_IO_HANDLERS
|
||||
{
|
||||
PFNVDD_INB inb_handler;
|
||||
PFNVDD_INW inw_handler;
|
||||
PFNVDD_INSB insb_handler;
|
||||
PFNVDD_INSW insw_handler;
|
||||
PFNVDD_OUTB outb_handler;
|
||||
PFNVDD_OUTW outw_handler;
|
||||
PFNVDD_OUTSB outsb_handler;
|
||||
PFNVDD_OUTSW outsw_handler;
|
||||
} VDD_IO_HANDLERS, *PVDD_IO_HANDLERS;
|
||||
|
||||
typedef struct _VDD_IO_PORTRANGE
|
||||
{
|
||||
WORD First;
|
||||
WORD Last;
|
||||
} VDD_IO_PORTRANGE, *PVDD_IO_PORTRANGE;
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
VDDInstallIOHook
|
||||
(
|
||||
HANDLE hVdd,
|
||||
WORD cPortRange,
|
||||
PVDD_IO_PORTRANGE pPortRange,
|
||||
PVDD_IO_HANDLERS IOhandler
|
||||
);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDDeInstallIOHook
|
||||
(
|
||||
HANDLE hVdd,
|
||||
WORD cPortRange,
|
||||
PVDD_IO_PORTRANGE pPortRange
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* Memory services
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VDM_V86,
|
||||
VDM_PM
|
||||
} VDM_MODE;
|
||||
|
||||
#ifndef MSW_PE
|
||||
#define MSW_PE 0x0001
|
||||
#endif
|
||||
|
||||
#define getMODE() ((getMSW() & MSW_PE) ? VDM_PM : VDM_V86)
|
||||
|
||||
PBYTE
|
||||
WINAPI
|
||||
Sim32pGetVDMPointer
|
||||
(
|
||||
IN ULONG Address,
|
||||
IN BOOLEAN ProtectedMode
|
||||
);
|
||||
|
||||
PBYTE
|
||||
WINAPI
|
||||
MGetVdmPointer
|
||||
(
|
||||
IN ULONG Address,
|
||||
IN ULONG Size,
|
||||
IN BOOLEAN ProtectedMode
|
||||
);
|
||||
|
||||
PVOID
|
||||
WINAPI
|
||||
VdmMapFlat
|
||||
(
|
||||
IN USHORT Segment,
|
||||
IN ULONG Offset,
|
||||
IN VDM_MODE Mode
|
||||
);
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
VdmFlushCache
|
||||
(
|
||||
IN USHORT Segment,
|
||||
IN ULONG Offset,
|
||||
IN ULONG Size,
|
||||
IN VDM_MODE Mode
|
||||
);
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
VdmUnmapFlat
|
||||
(
|
||||
IN USHORT Segment,
|
||||
IN ULONG Offset,
|
||||
IN PVOID Buffer,
|
||||
IN VDM_MODE Mode
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* vddsvc.h
|
||||
*
|
||||
* Windows NT Device Driver Kit
|
||||
*
|
||||
* This file is part of the ReactOS DDK package.
|
||||
*
|
||||
* Contributors:
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*
|
||||
* THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
*
|
||||
* This source code is offered for use in the public domain. You may
|
||||
* use, modify or distribute it freely.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but
|
||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||
* DISCLAIMED. This includes but is not limited to warranties of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _NT_VDD
|
||||
#include <nt_vdd.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupts services
|
||||
*/
|
||||
#define ICA_MASTER 0
|
||||
#define ICA_SLAVE 1
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
call_ica_hw_interrupt
|
||||
(
|
||||
INT ms,
|
||||
BYTE line,
|
||||
INT count
|
||||
);
|
||||
|
||||
#define VDDSimulateInterrupt(ms, line, count) \
|
||||
call_ica_hw_interrupt((ms), (line), (count)) // Windows specifies a count of 1 ...
|
||||
|
||||
|
||||
/*
|
||||
* Registers manipulation
|
||||
*/
|
||||
PVOID WINAPI getIntelRegistersPointer(VOID);
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
ULONG WINAPI getEAX(VOID);
|
||||
VOID WINAPI setEAX(ULONG);
|
||||
USHORT WINAPI getAX(VOID);
|
||||
VOID WINAPI setAX(USHORT);
|
||||
UCHAR WINAPI getAH(VOID);
|
||||
VOID WINAPI setAH(UCHAR);
|
||||
UCHAR WINAPI getAL(VOID);
|
||||
VOID WINAPI setAL(UCHAR);
|
||||
|
||||
ULONG WINAPI getEBX(VOID);
|
||||
VOID WINAPI setEBX(ULONG);
|
||||
USHORT WINAPI getBX(VOID);
|
||||
VOID WINAPI setBX(USHORT);
|
||||
UCHAR WINAPI getBH(VOID);
|
||||
VOID WINAPI setBH(UCHAR);
|
||||
UCHAR WINAPI getBL(VOID);
|
||||
VOID WINAPI setBL(UCHAR);
|
||||
|
||||
ULONG WINAPI getECX(VOID);
|
||||
VOID WINAPI setECX(ULONG);
|
||||
USHORT WINAPI getCX(VOID);
|
||||
VOID WINAPI setCX(USHORT);
|
||||
UCHAR WINAPI getCH(VOID);
|
||||
VOID WINAPI setCH(UCHAR);
|
||||
UCHAR WINAPI getCL(VOID);
|
||||
VOID WINAPI setCL(UCHAR);
|
||||
|
||||
ULONG WINAPI getEDX(VOID);
|
||||
VOID WINAPI setEDX(ULONG);
|
||||
USHORT WINAPI getDX(VOID);
|
||||
VOID WINAPI setDX(USHORT);
|
||||
UCHAR WINAPI getDH(VOID);
|
||||
VOID WINAPI setDH(UCHAR);
|
||||
UCHAR WINAPI getDL(VOID);
|
||||
VOID WINAPI setDL(UCHAR);
|
||||
|
||||
|
||||
|
||||
ULONG WINAPI getESP(VOID);
|
||||
VOID WINAPI setESP(ULONG);
|
||||
USHORT WINAPI getSP(VOID);
|
||||
VOID WINAPI setSP(USHORT);
|
||||
|
||||
ULONG WINAPI getEBP(VOID);
|
||||
VOID WINAPI setEBP(ULONG);
|
||||
USHORT WINAPI getBP(VOID);
|
||||
VOID WINAPI setBP(USHORT);
|
||||
|
||||
ULONG WINAPI getESI(VOID);
|
||||
VOID WINAPI setESI(ULONG);
|
||||
USHORT WINAPI getSI(VOID);
|
||||
VOID WINAPI setSI(USHORT);
|
||||
|
||||
ULONG WINAPI getEDI(VOID);
|
||||
VOID WINAPI setEDI(ULONG);
|
||||
USHORT WINAPI getDI(VOID);
|
||||
VOID WINAPI setDI(USHORT);
|
||||
|
||||
ULONG WINAPI getEIP(VOID);
|
||||
VOID WINAPI setEIP(ULONG);
|
||||
USHORT WINAPI getIP(VOID);
|
||||
VOID WINAPI setIP(USHORT);
|
||||
|
||||
USHORT WINAPI getCS(VOID);
|
||||
VOID WINAPI setCS(USHORT);
|
||||
USHORT WINAPI getSS(VOID);
|
||||
VOID WINAPI setSS(USHORT);
|
||||
USHORT WINAPI getDS(VOID);
|
||||
VOID WINAPI setDS(USHORT);
|
||||
USHORT WINAPI getES(VOID);
|
||||
VOID WINAPI setES(USHORT);
|
||||
USHORT WINAPI getFS(VOID);
|
||||
VOID WINAPI setFS(USHORT);
|
||||
USHORT WINAPI getGS(VOID);
|
||||
VOID WINAPI setGS(USHORT);
|
||||
|
||||
ULONG WINAPI getCF(VOID);
|
||||
VOID WINAPI setCF(ULONG);
|
||||
ULONG WINAPI getPF(VOID);
|
||||
VOID WINAPI setPF(ULONG);
|
||||
ULONG WINAPI getAF(VOID);
|
||||
VOID WINAPI setAF(ULONG);
|
||||
ULONG WINAPI getZF(VOID);
|
||||
VOID WINAPI setZF(ULONG);
|
||||
ULONG WINAPI getSF(VOID);
|
||||
VOID WINAPI setSF(ULONG);
|
||||
ULONG WINAPI getIF(VOID);
|
||||
VOID WINAPI setIF(ULONG);
|
||||
ULONG WINAPI getDF(VOID);
|
||||
VOID WINAPI setDF(ULONG);
|
||||
ULONG WINAPI getOF(VOID);
|
||||
VOID WINAPI setOF(ULONG);
|
||||
|
||||
ULONG WINAPI getEFLAGS(VOID);
|
||||
VOID WINAPI setEFLAGS(ULONG);
|
||||
|
||||
USHORT WINAPI getMSW(VOID);
|
||||
VOID WINAPI setMSW(USHORT);
|
||||
|
||||
#else
|
||||
|
||||
ULONG WINAPI c_getEAX(VOID);
|
||||
VOID WINAPI c_setEAX(ULONG);
|
||||
USHORT WINAPI c_getAX(VOID);
|
||||
VOID WINAPI c_setAX(USHORT);
|
||||
UCHAR WINAPI c_getAH(VOID);
|
||||
VOID WINAPI c_setAH(UCHAR);
|
||||
UCHAR WINAPI c_getAL(VOID);
|
||||
VOID WINAPI c_setAL(UCHAR);
|
||||
|
||||
ULONG WINAPI c_getEBX(VOID);
|
||||
VOID WINAPI c_setEBX(ULONG);
|
||||
USHORT WINAPI c_getBX(VOID);
|
||||
VOID WINAPI c_setBX(USHORT);
|
||||
UCHAR WINAPI c_getBH(VOID);
|
||||
VOID WINAPI c_setBH(UCHAR);
|
||||
UCHAR WINAPI c_getBL(VOID);
|
||||
VOID WINAPI c_setBL(UCHAR);
|
||||
|
||||
ULONG WINAPI c_getECX(VOID);
|
||||
VOID WINAPI c_setECX(ULONG);
|
||||
USHORT WINAPI c_getCX(VOID);
|
||||
VOID WINAPI c_setCX(USHORT);
|
||||
UCHAR WINAPI c_getCH(VOID);
|
||||
VOID WINAPI c_setCH(UCHAR);
|
||||
UCHAR WINAPI c_getCL(VOID);
|
||||
VOID WINAPI c_setCL(UCHAR);
|
||||
|
||||
ULONG WINAPI c_getEDX(VOID);
|
||||
VOID WINAPI c_setEDX(ULONG);
|
||||
USHORT WINAPI c_getDX(VOID);
|
||||
VOID WINAPI c_setDX(USHORT);
|
||||
UCHAR WINAPI c_getDH(VOID);
|
||||
VOID WINAPI c_setDH(UCHAR);
|
||||
UCHAR WINAPI c_getDL(VOID);
|
||||
VOID WINAPI c_setDL(UCHAR);
|
||||
|
||||
|
||||
|
||||
ULONG WINAPI c_getESP(VOID);
|
||||
VOID WINAPI c_setESP(ULONG);
|
||||
USHORT WINAPI c_getSP(VOID);
|
||||
VOID WINAPI c_setSP(USHORT);
|
||||
|
||||
ULONG WINAPI c_getEBP(VOID);
|
||||
VOID WINAPI c_setEBP(ULONG);
|
||||
USHORT WINAPI c_getBP(VOID);
|
||||
VOID WINAPI c_setBP(USHORT);
|
||||
|
||||
ULONG WINAPI c_getESI(VOID);
|
||||
VOID WINAPI c_setESI(ULONG);
|
||||
USHORT WINAPI c_getSI(VOID);
|
||||
VOID WINAPI c_setSI(USHORT);
|
||||
|
||||
ULONG WINAPI c_getEDI(VOID);
|
||||
VOID WINAPI c_setEDI(ULONG);
|
||||
USHORT WINAPI c_getDI(VOID);
|
||||
VOID WINAPI c_setDI(USHORT);
|
||||
|
||||
ULONG WINAPI c_getEIP(VOID);
|
||||
VOID WINAPI c_setEIP(ULONG);
|
||||
USHORT WINAPI c_getIP(VOID);
|
||||
VOID WINAPI c_setIP(USHORT);
|
||||
|
||||
USHORT WINAPI c_getCS(VOID);
|
||||
VOID WINAPI c_setCS(USHORT);
|
||||
USHORT WINAPI c_getSS(VOID);
|
||||
VOID WINAPI c_setSS(USHORT);
|
||||
USHORT WINAPI c_getDS(VOID);
|
||||
VOID WINAPI c_setDS(USHORT);
|
||||
USHORT WINAPI c_getES(VOID);
|
||||
VOID WINAPI c_setES(USHORT);
|
||||
USHORT WINAPI c_getFS(VOID);
|
||||
VOID WINAPI c_setFS(USHORT);
|
||||
USHORT WINAPI c_getGS(VOID);
|
||||
VOID WINAPI c_setGS(USHORT);
|
||||
|
||||
ULONG WINAPI c_getCF(VOID);
|
||||
VOID WINAPI c_setCF(ULONG);
|
||||
ULONG WINAPI c_getPF(VOID);
|
||||
VOID WINAPI c_setPF(ULONG);
|
||||
ULONG WINAPI c_getAF(VOID);
|
||||
VOID WINAPI c_setAF(ULONG);
|
||||
ULONG WINAPI c_getZF(VOID);
|
||||
VOID WINAPI c_setZF(ULONG);
|
||||
ULONG WINAPI c_getSF(VOID);
|
||||
VOID WINAPI c_setSF(ULONG);
|
||||
ULONG WINAPI c_getIF(VOID);
|
||||
VOID WINAPI c_setIF(ULONG);
|
||||
ULONG WINAPI c_getDF(VOID);
|
||||
VOID WINAPI c_setDF(ULONG);
|
||||
ULONG WINAPI c_getOF(VOID);
|
||||
VOID WINAPI c_setOF(ULONG);
|
||||
|
||||
USHORT WINAPI c_getMSW(VOID);
|
||||
VOID WINAPI c_setMSW(USHORT);
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* fast486.h
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _FAST486_H_
|
||||
#define _FAST486_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#ifndef FASTCALL
|
||||
#define FASTCALL __fastcall
|
||||
#endif
|
||||
|
||||
#define FAST486_NUM_GEN_REGS 8
|
||||
#define FAST486_NUM_SEG_REGS 6
|
||||
#define FAST486_NUM_CTRL_REGS 3
|
||||
#define FAST486_NUM_DBG_REGS 6
|
||||
#define FAST486_NUM_FPU_REGS 8
|
||||
|
||||
#define FAST486_CR0_PE (1 << 0)
|
||||
#define FAST486_CR0_MP (1 << 1)
|
||||
#define FAST486_CR0_EM (1 << 2)
|
||||
#define FAST486_CR0_TS (1 << 3)
|
||||
#define FAST486_CR0_ET (1 << 4)
|
||||
#define FAST486_CR0_NE (1 << 5)
|
||||
#define FAST486_CR0_WP (1 << 16)
|
||||
#define FAST486_CR0_AM (1 << 18)
|
||||
#define FAST486_CR0_NW (1 << 29)
|
||||
#define FAST486_CR0_CD (1 << 30)
|
||||
#define FAST486_CR0_PG (1 << 31)
|
||||
|
||||
#define FAST486_DR4_B0 (1 << 0)
|
||||
#define FAST486_DR4_B1 (1 << 1)
|
||||
#define FAST486_DR4_B2 (1 << 2)
|
||||
#define FAST486_DR4_B3 (1 << 3)
|
||||
#define FAST486_DR4_BD (1 << 13)
|
||||
#define FAST486_DR4_BS (1 << 14)
|
||||
#define FAST486_DR4_BT (1 << 15)
|
||||
|
||||
#define FAST486_DR5_L0 (1 << 0)
|
||||
#define FAST486_DR5_G0 (1 << 1)
|
||||
#define FAST486_DR5_L1 (1 << 2)
|
||||
#define FAST486_DR5_G1 (1 << 3)
|
||||
#define FAST486_DR5_L2 (1 << 4)
|
||||
#define FAST486_DR5_G2 (1 << 5)
|
||||
#define FAST486_DR5_L3 (1 << 6)
|
||||
#define FAST486_DR5_G3 (1 << 7)
|
||||
#define FAST486_DR5_LE (1 << 8)
|
||||
#define FAST486_DR5_GE (1 << 9)
|
||||
#define FAST486_DR5_GD (1 << 13)
|
||||
|
||||
#define FAST486_DBG_BREAK_EXEC 0
|
||||
#define FAST486_DBG_BREAK_WRITE 1
|
||||
#define FAST486_DBG_BREAK_READWRITE 3
|
||||
|
||||
#define FAST486_DR4_RESERVED 0xFFFF1FF0
|
||||
#define FAST486_DR5_RESERVED 0x0000DC00
|
||||
|
||||
#define FAST486_IDT_TASK_GATE 0x5
|
||||
#define FAST486_IDT_INT_GATE 0x6
|
||||
#define FAST486_IDT_TRAP_GATE 0x7
|
||||
#define FAST486_IDT_INT_GATE_32 0xE
|
||||
#define FAST486_IDT_TRAP_GATE_32 0xF
|
||||
|
||||
#define FAST486_LDT_SIGNATURE 0x02
|
||||
#define FAST486_TSS_SIGNATURE 0x09
|
||||
|
||||
#define FAST486_PREFIX_SEG (1 << 0)
|
||||
#define FAST486_PREFIX_OPSIZE (1 << 1)
|
||||
#define FAST486_PREFIX_ADSIZE (1 << 2)
|
||||
#define FAST486_PREFIX_LOCK (1 << 3)
|
||||
#define FAST486_PREFIX_REPNZ (1 << 4)
|
||||
#define FAST486_PREFIX_REP (1 << 5)
|
||||
|
||||
struct _FAST486_STATE;
|
||||
typedef struct _FAST486_STATE FAST486_STATE, *PFAST486_STATE;
|
||||
|
||||
typedef enum _FAST486_GEN_REGS
|
||||
{
|
||||
FAST486_REG_EAX,
|
||||
FAST486_REG_ECX,
|
||||
FAST486_REG_EDX,
|
||||
FAST486_REG_EBX,
|
||||
FAST486_REG_ESP,
|
||||
FAST486_REG_EBP,
|
||||
FAST486_REG_ESI,
|
||||
FAST486_REG_EDI
|
||||
} FAST486_GEN_REGS, *PFAST486_GEN_REGS;
|
||||
|
||||
typedef enum _FAST486_SEG_REGS
|
||||
{
|
||||
FAST486_REG_ES,
|
||||
FAST486_REG_CS,
|
||||
FAST486_REG_SS,
|
||||
FAST486_REG_DS,
|
||||
FAST486_REG_FS,
|
||||
FAST486_REG_GS
|
||||
} FAST486_SEG_REGS, *PFAST486_SEG_REGS;
|
||||
|
||||
typedef enum _FAST486_CTRL_REGS
|
||||
{
|
||||
FAST486_REG_CR0 = 0,
|
||||
FAST486_REG_CR2 = 1,
|
||||
FAST486_REG_CR3 = 2,
|
||||
} FAST486_CTRL_REGS, *PFAST486_CTRL_REGS;
|
||||
|
||||
typedef enum _FAST486_DBG_REGS
|
||||
{
|
||||
FAST486_REG_DR0 = 0,
|
||||
FAST486_REG_DR1 = 1,
|
||||
FAST486_REG_DR2 = 2,
|
||||
FAST486_REG_DR3 = 3,
|
||||
FAST486_REG_DR4 = 4,
|
||||
FAST486_REG_DR5 = 5,
|
||||
FAST486_REG_DR6 = 4, // alias to DR4
|
||||
FAST486_REG_DR7 = 5 // alias to DR5
|
||||
} FAST486_DBG_REGS, *PFAST486_DBG_REGS;
|
||||
|
||||
typedef enum _FAST486_EXCEPTIONS
|
||||
{
|
||||
FAST486_EXCEPTION_DE = 0x00,
|
||||
FAST486_EXCEPTION_DB = 0x01,
|
||||
FAST486_EXCEPTION_BP = 0x03,
|
||||
FAST486_EXCEPTION_OF = 0x04,
|
||||
FAST486_EXCEPTION_BR = 0x05,
|
||||
FAST486_EXCEPTION_UD = 0x06,
|
||||
FAST486_EXCEPTION_NM = 0x07,
|
||||
FAST486_EXCEPTION_DF = 0x08,
|
||||
FAST486_EXCEPTION_TS = 0x0A,
|
||||
FAST486_EXCEPTION_NP = 0x0B,
|
||||
FAST486_EXCEPTION_SS = 0x0C,
|
||||
FAST486_EXCEPTION_GP = 0x0D,
|
||||
FAST486_EXCEPTION_PF = 0x0E,
|
||||
FAST486_EXCEPTION_MF = 0x10,
|
||||
FAST486_EXCEPTION_AC = 0x11,
|
||||
FAST486_EXCEPTION_MC = 0x12
|
||||
} FAST486_EXCEPTIONS, *PFAST486_EXCEPTIONS;
|
||||
|
||||
typedef enum _FAST486_INT_STATUS
|
||||
{
|
||||
FAST486_INT_NONE = 0,
|
||||
FAST486_INT_EXECUTE = 1,
|
||||
FAST486_INT_SIGNAL = 2
|
||||
} FAST486_INT_STATUS, *PFAST486_INT_STATUS;
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI *FAST486_MEM_READ_PROC)
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Address,
|
||||
PVOID Buffer,
|
||||
ULONG Size
|
||||
);
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI *FAST486_MEM_WRITE_PROC)
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Address,
|
||||
PVOID Buffer,
|
||||
ULONG Size
|
||||
);
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI *FAST486_IO_READ_PROC)
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Port,
|
||||
PVOID Buffer,
|
||||
ULONG DataCount,
|
||||
UCHAR DataSize
|
||||
);
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI *FAST486_IO_WRITE_PROC)
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Port,
|
||||
PVOID Buffer,
|
||||
ULONG DataCount,
|
||||
UCHAR DataSize
|
||||
);
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI *FAST486_IDLE_PROC)
|
||||
(
|
||||
PFAST486_STATE State
|
||||
);
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI *FAST486_BOP_PROC)
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
UCHAR BopCode
|
||||
);
|
||||
|
||||
typedef
|
||||
UCHAR
|
||||
(NTAPI *FAST486_INT_ACK_PROC)
|
||||
(
|
||||
PFAST486_STATE State
|
||||
);
|
||||
|
||||
typedef union _FAST486_REG
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
UCHAR LowByte;
|
||||
UCHAR HighByte;
|
||||
};
|
||||
USHORT LowWord;
|
||||
};
|
||||
ULONG Long;
|
||||
} FAST486_REG, *PFAST486_REG;
|
||||
|
||||
typedef struct _FAST486_SEG_REG
|
||||
{
|
||||
USHORT Selector;
|
||||
|
||||
/* Descriptor cache */
|
||||
ULONG Accessed : 1;
|
||||
ULONG ReadWrite : 1;
|
||||
ULONG DirConf : 1;
|
||||
ULONG Executable : 1;
|
||||
ULONG SystemType : 1;
|
||||
ULONG Dpl : 2;
|
||||
ULONG Present : 1;
|
||||
ULONG Size : 1;
|
||||
ULONG Limit;
|
||||
ULONG Base;
|
||||
} FAST486_SEG_REG, *PFAST486_SEG_REG;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USHORT Selector;
|
||||
ULONG Base;
|
||||
ULONG Limit;
|
||||
} FAST486_LDT_REG;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USHORT Selector;
|
||||
ULONG Base;
|
||||
ULONG Limit;
|
||||
BOOLEAN Busy;
|
||||
} FAST486_TASK_REG, *PFAST486_TASK_REG;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Limit : 16;
|
||||
ULONG Base : 16;
|
||||
ULONG BaseMid : 8;
|
||||
ULONG Accessed : 1;
|
||||
ULONG ReadWrite : 1;
|
||||
ULONG DirConf : 1;
|
||||
ULONG Executable : 1;
|
||||
ULONG SystemType : 1;
|
||||
ULONG Dpl : 2;
|
||||
ULONG Present : 1;
|
||||
ULONG LimitHigh : 4;
|
||||
ULONG Avl : 1;
|
||||
ULONG Reserved : 1;
|
||||
ULONG Size : 1;
|
||||
ULONG Granularity : 1;
|
||||
ULONG BaseHigh : 8;
|
||||
} FAST486_GDT_ENTRY, *PFAST486_GDT_ENTRY;
|
||||
|
||||
/* Verify the structure size */
|
||||
C_ASSERT(sizeof(FAST486_GDT_ENTRY) == sizeof(ULONGLONG));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Limit : 16;
|
||||
ULONG Base : 16;
|
||||
ULONG BaseMid : 8;
|
||||
ULONG Signature : 5;
|
||||
ULONG Dpl : 2;
|
||||
ULONG Present : 1;
|
||||
ULONG LimitHigh : 4;
|
||||
ULONG Avl : 1;
|
||||
ULONG Reserved : 2;
|
||||
ULONG Granularity : 1;
|
||||
ULONG BaseHigh : 8;
|
||||
} FAST486_SYSTEM_DESCRIPTOR, *PFAST486_SYSTEM_DESCRIPTOR;
|
||||
|
||||
/* Verify the structure size */
|
||||
C_ASSERT(sizeof(FAST486_SYSTEM_DESCRIPTOR) == sizeof(ULONGLONG));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Offset : 16;
|
||||
ULONG Selector : 16;
|
||||
ULONG ParamCount : 5;
|
||||
ULONG Reserved : 3;
|
||||
ULONG Type : 4;
|
||||
ULONG SystemType : 1;
|
||||
ULONG Dpl : 2;
|
||||
ULONG Present : 1;
|
||||
ULONG OffsetHigh : 16;
|
||||
} FAST486_CALL_GATE, *PFAST486_CALL_GATE;
|
||||
|
||||
/* Verify the structure size */
|
||||
C_ASSERT(sizeof(FAST486_CALL_GATE) == sizeof(ULONGLONG));
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG Offset : 16;
|
||||
ULONG Selector : 16;
|
||||
ULONG Zero : 8;
|
||||
ULONG Type : 4;
|
||||
ULONG Storage : 1;
|
||||
ULONG Dpl : 2;
|
||||
ULONG Present : 1;
|
||||
ULONG OffsetHigh : 16;
|
||||
} FAST486_IDT_ENTRY, *PFAST486_IDT_ENTRY;
|
||||
|
||||
/* Verify the structure size */
|
||||
C_ASSERT(sizeof(FAST486_IDT_ENTRY) == sizeof(ULONGLONG));
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct _FAST486_TABLE_REG
|
||||
{
|
||||
USHORT Size;
|
||||
ULONG Address;
|
||||
} FAST486_TABLE_REG, *PFAST486_TABLE_REG;
|
||||
|
||||
typedef union _FAST486_FLAGS_REG
|
||||
{
|
||||
USHORT LowWord;
|
||||
ULONG Long;
|
||||
|
||||
struct
|
||||
{
|
||||
ULONG Cf : 1;
|
||||
ULONG AlwaysSet : 1;
|
||||
ULONG Pf : 1;
|
||||
ULONG Reserved0 : 1;
|
||||
ULONG Af : 1;
|
||||
ULONG Reserved1 : 1;
|
||||
ULONG Zf : 1;
|
||||
ULONG Sf : 1;
|
||||
ULONG Tf : 1;
|
||||
ULONG If : 1;
|
||||
ULONG Df : 1;
|
||||
ULONG Of : 1;
|
||||
ULONG Iopl : 2;
|
||||
ULONG Nt : 1;
|
||||
ULONG Reserved2 : 1;
|
||||
ULONG Rf : 1;
|
||||
ULONG Vm : 1;
|
||||
ULONG Ac : 1;
|
||||
|
||||
// ULONG Reserved : 13;
|
||||
};
|
||||
} FAST486_FLAGS_REG, *PFAST486_FLAGS_REG;
|
||||
|
||||
typedef struct _FAST486_TSS
|
||||
{
|
||||
ULONG Link;
|
||||
ULONG Esp0;
|
||||
ULONG Ss0;
|
||||
ULONG Esp1;
|
||||
ULONG Ss1;
|
||||
ULONG Esp2;
|
||||
ULONG Ss2;
|
||||
ULONG Cr3;
|
||||
ULONG Eip;
|
||||
ULONG Eflags;
|
||||
ULONG Eax;
|
||||
ULONG Ecx;
|
||||
ULONG Edx;
|
||||
ULONG Ebx;
|
||||
ULONG Esp;
|
||||
ULONG Ebp;
|
||||
ULONG Esi;
|
||||
ULONG Edi;
|
||||
ULONG Es;
|
||||
ULONG Cs;
|
||||
ULONG Ss;
|
||||
ULONG Ds;
|
||||
ULONG Fs;
|
||||
ULONG Gs;
|
||||
ULONG Ldtr;
|
||||
ULONG IopbOffset;
|
||||
} FAST486_TSS, *PFAST486_TSS;
|
||||
|
||||
typedef struct _FAST486_FPU_DATA_REG
|
||||
{
|
||||
ULONGLONG Mantissa;
|
||||
USHORT Exponent;
|
||||
} FAST486_FPU_DATA_REG, *PFAST486_FPU_DATA_REG;
|
||||
|
||||
typedef union _FAST486_FPU_STATUS_REG
|
||||
{
|
||||
USHORT Value;
|
||||
|
||||
struct
|
||||
{
|
||||
ULONG Ie : 1;
|
||||
ULONG De : 1;
|
||||
ULONG Ze : 1;
|
||||
ULONG Oe : 1;
|
||||
ULONG Ue : 1;
|
||||
ULONG Pe : 1;
|
||||
ULONG Sf : 1;
|
||||
ULONG Es : 1;
|
||||
ULONG Code0 : 1;
|
||||
ULONG Code1 : 1;
|
||||
ULONG Code2 : 1;
|
||||
ULONG Top : 3;
|
||||
ULONG Code3 : 1;
|
||||
ULONG Busy : 1;
|
||||
};
|
||||
} FAST486_FPU_STATUS_REG, *PFAST486_FPU_STATUS_REG;
|
||||
|
||||
typedef union _FAST486_FPU_CONTROL_REG
|
||||
{
|
||||
USHORT Value;
|
||||
|
||||
struct
|
||||
{
|
||||
ULONG Im : 1;
|
||||
ULONG Dm : 1;
|
||||
ULONG Zm : 1;
|
||||
ULONG Om : 1;
|
||||
ULONG Um : 1;
|
||||
ULONG Pm : 1;
|
||||
ULONG Reserved : 2;
|
||||
ULONG Pc : 2;
|
||||
ULONG Rc : 2;
|
||||
ULONG Inf : 1;
|
||||
// ULONG Reserved1 : 3;
|
||||
};
|
||||
} FAST486_FPU_CONTROL_REG, *PFAST486_FPU_CONTROL_REG;
|
||||
|
||||
struct _FAST486_STATE
|
||||
{
|
||||
FAST486_MEM_READ_PROC MemReadCallback;
|
||||
FAST486_MEM_WRITE_PROC MemWriteCallback;
|
||||
FAST486_IO_READ_PROC IoReadCallback;
|
||||
FAST486_IO_WRITE_PROC IoWriteCallback;
|
||||
FAST486_IDLE_PROC IdleCallback;
|
||||
FAST486_BOP_PROC BopCallback;
|
||||
FAST486_INT_ACK_PROC IntAckCallback;
|
||||
FAST486_REG GeneralRegs[FAST486_NUM_GEN_REGS];
|
||||
FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS];
|
||||
FAST486_REG InstPtr, SavedInstPtr;
|
||||
FAST486_FLAGS_REG Flags;
|
||||
FAST486_TABLE_REG Gdtr, Idtr;
|
||||
FAST486_LDT_REG Ldtr;
|
||||
FAST486_TASK_REG TaskReg;
|
||||
UCHAR Cpl;
|
||||
ULONG ControlRegisters[FAST486_NUM_CTRL_REGS];
|
||||
ULONG DebugRegisters[FAST486_NUM_DBG_REGS];
|
||||
ULONG ExceptionCount;
|
||||
ULONG PrefixFlags;
|
||||
FAST486_SEG_REGS SegmentOverride;
|
||||
FAST486_INT_STATUS IntStatus;
|
||||
UCHAR PendingIntNum;
|
||||
PULONG Tlb;
|
||||
FAST486_FPU_DATA_REG FpuRegisters[FAST486_NUM_FPU_REGS];
|
||||
FAST486_FPU_STATUS_REG FpuStatus;
|
||||
FAST486_FPU_CONTROL_REG FpuControl;
|
||||
USHORT FpuTag;
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Initialize(PFAST486_STATE State,
|
||||
FAST486_MEM_READ_PROC MemReadCallback,
|
||||
FAST486_MEM_WRITE_PROC MemWriteCallback,
|
||||
FAST486_IO_READ_PROC IoReadCallback,
|
||||
FAST486_IO_WRITE_PROC IoWriteCallback,
|
||||
FAST486_IDLE_PROC IdleCallback,
|
||||
FAST486_BOP_PROC BopCallback,
|
||||
FAST486_INT_ACK_PROC IntAckCallback,
|
||||
PULONG Tlb);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Reset(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Continue(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486StepInto(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486StepOver(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486StepOut(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486DumpState(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Interrupt(PFAST486_STATE State, UCHAR Number);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486InterruptSignal(PFAST486_STATE State);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486SetStack(PFAST486_STATE State, USHORT Segment, ULONG Offset);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486SetSegment
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
FAST486_SEG_REGS Segment,
|
||||
USHORT Selector
|
||||
);
|
||||
|
||||
#endif // _FAST486_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Base API Server DLL
|
||||
* FILE: include/reactos/subsys/win/vdm.h
|
||||
* PURPOSE: Public definitions for the Virtual Dos Machine
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Alex Ionescu ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _VDM_H
|
||||
#define _VDM_H
|
||||
|
||||
#pragma once
|
||||
|
||||
/* CONSTANTS & TYPES **********************************************************/
|
||||
|
||||
typedef enum _VDM_ENTRY_CODE
|
||||
{
|
||||
VdmEntryUndo,
|
||||
VdmEntryUpdateProcess,
|
||||
VdmEntryUpdateControlCHandler
|
||||
} VDM_ENTRY_CODE;
|
||||
|
||||
//
|
||||
// Undo States
|
||||
//
|
||||
#define VDM_UNDO_PARTIAL 0x01
|
||||
#define VDM_UNDO_FULL 0x02
|
||||
#define VDM_UNDO_REUSE 0x04
|
||||
#define VDM_UNDO_COMPLETED 0x08
|
||||
|
||||
//
|
||||
// Binary Types to share with VDM
|
||||
//
|
||||
#define BINARY_TYPE_EXE 0x01
|
||||
#define BINARY_TYPE_COM 0x02
|
||||
#define BINARY_TYPE_PIF 0x03
|
||||
#define BINARY_TYPE_DOS 0x10
|
||||
#define BINARY_TYPE_SEPARATE_WOW 0x20
|
||||
#define BINARY_TYPE_WOW 0x40
|
||||
#define BINARY_TYPE_WOW_EX 0x80
|
||||
|
||||
//
|
||||
// VDM States
|
||||
//
|
||||
#define VDM_NOT_LOADED 0x01
|
||||
#define VDM_NOT_READY 0x02
|
||||
#define VDM_READY 0x04
|
||||
|
||||
//
|
||||
// VDM Flags
|
||||
//
|
||||
#define VDM_FLAG_FIRST_TASK 0x01
|
||||
#define VDM_FLAG_WOW 0x02
|
||||
#define VDM_FLAG_DOS 0x04
|
||||
#define VDM_FLAG_RETRY 0x08
|
||||
#define VDM_INC_REENTER_COUNT 0x10
|
||||
#define VDM_DEC_REENTER_COUNT 0x20
|
||||
#define VDM_FLAG_NESTED_TASK 0x40
|
||||
#define VDM_FLAG_DONT_WAIT 0x80
|
||||
#define VDM_GET_FIRST_COMMAND 0x100
|
||||
#define VDM_GET_ENVIRONMENT 0x400
|
||||
#define VDM_FLAG_SEPARATE_WOW 0x800
|
||||
#define VDM_LIST_WOW_PROCESSES 0x1000
|
||||
#define VDM_LIST_WOW_TASKS 0x4000
|
||||
#define VDM_ADD_WOW_TASK 0x8000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG TaskId;
|
||||
ULONG CreationFlags;
|
||||
ULONG ExitCode;
|
||||
ULONG CodePage;
|
||||
HANDLE StdIn;
|
||||
HANDLE StdOut;
|
||||
HANDLE StdErr;
|
||||
LPSTR CmdLine;
|
||||
LPSTR AppName;
|
||||
LPSTR PifFile;
|
||||
LPSTR CurDirectory;
|
||||
LPSTR Env;
|
||||
ULONG EnvLen;
|
||||
STARTUPINFOA StartupInfo;
|
||||
LPSTR Desktop;
|
||||
ULONG DesktopLen;
|
||||
LPSTR Title;
|
||||
ULONG TitleLen;
|
||||
LPVOID Reserved;
|
||||
ULONG ReservedLen;
|
||||
USHORT CmdLen;
|
||||
USHORT AppLen;
|
||||
USHORT PifLen;
|
||||
USHORT CurDirectoryLen;
|
||||
USHORT VDMState;
|
||||
USHORT CurrentDrive;
|
||||
BOOLEAN ComingFromBat;
|
||||
} VDM_COMMAND_INFO, *PVDM_COMMAND_INFO;
|
||||
|
||||
|
||||
/* FUNCTION PROTOTYPES ********************************************************/
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
GetNextVDMCommand(
|
||||
IN OUT PVDM_COMMAND_INFO CommandData OPTIONAL
|
||||
);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
ExitVDM(
|
||||
IN BOOL IsWow,
|
||||
IN ULONG iWowTask
|
||||
);
|
||||
|
||||
#endif // _VDM_H
|
||||
|
||||
/* EOF */
|
||||
@@ -11,6 +11,7 @@ add_subdirectory(cryptlib)
|
||||
#add_subdirectory(dnslib) Nothing links to this lib.
|
||||
add_subdirectory(drivers)
|
||||
add_subdirectory(epsapi)
|
||||
add_subdirectory(fast486)
|
||||
add_subdirectory(fslib)
|
||||
add_subdirectory(lsalib)
|
||||
add_subdirectory(ppcmmu)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
include_directories(${REACTOS_SOURCE_DIR}/include/reactos/libs/fast486)
|
||||
|
||||
list(APPEND SOURCE
|
||||
fast486.c
|
||||
opcodes.c
|
||||
opgroups.c
|
||||
extraops.c
|
||||
common.c
|
||||
fpu.c)
|
||||
|
||||
add_library(fast486 ${SOURCE})
|
||||
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* common.c
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <windef.h>
|
||||
|
||||
// #define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#include <fast486.h>
|
||||
#include "common.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN
|
||||
Fast486ReadMemory(PFAST486_STATE State,
|
||||
FAST486_SEG_REGS SegmentReg,
|
||||
ULONG Offset,
|
||||
BOOLEAN InstFetch,
|
||||
PVOID Buffer,
|
||||
ULONG Size)
|
||||
{
|
||||
ULONG LinearAddress;
|
||||
PFAST486_SEG_REG CachedDescriptor;
|
||||
|
||||
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
|
||||
|
||||
/* Get the cached descriptor */
|
||||
CachedDescriptor = &State->SegmentRegs[SegmentReg];
|
||||
|
||||
if ((Offset + Size - 1) > CachedDescriptor->Limit)
|
||||
{
|
||||
/* Read beyond limit */
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check for protected mode */
|
||||
if (State->ControlRegisters[0] & FAST486_CR0_PE)
|
||||
{
|
||||
/* Privilege checks */
|
||||
|
||||
if (!CachedDescriptor->Present)
|
||||
{
|
||||
Fast486Exception(State, FAST486_EXCEPTION_NP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((!InstFetch && (GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl))
|
||||
|| (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl))
|
||||
{
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (InstFetch)
|
||||
{
|
||||
if (!CachedDescriptor->Executable)
|
||||
{
|
||||
/* Data segment not executable */
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite))
|
||||
{
|
||||
/* Code segment not readable */
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the linear address */
|
||||
LinearAddress = CachedDescriptor->Base + Offset;
|
||||
|
||||
/* Read from the linear address */
|
||||
return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Fast486WriteMemory(PFAST486_STATE State,
|
||||
FAST486_SEG_REGS SegmentReg,
|
||||
ULONG Offset,
|
||||
PVOID Buffer,
|
||||
ULONG Size)
|
||||
{
|
||||
ULONG LinearAddress;
|
||||
PFAST486_SEG_REG CachedDescriptor;
|
||||
|
||||
ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
|
||||
|
||||
/* Get the cached descriptor */
|
||||
CachedDescriptor = &State->SegmentRegs[SegmentReg];
|
||||
|
||||
if ((Offset + Size - 1) > CachedDescriptor->Limit)
|
||||
{
|
||||
/* Write beyond limit */
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check for protected mode */
|
||||
if (State->ControlRegisters[0] & FAST486_CR0_PE)
|
||||
{
|
||||
/* Privilege checks */
|
||||
|
||||
if (!CachedDescriptor->Present)
|
||||
{
|
||||
Fast486Exception(State, FAST486_EXCEPTION_NP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
|
||||
|| (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl))
|
||||
{
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (CachedDescriptor->Executable)
|
||||
{
|
||||
/* Code segment not writable */
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
else if (!CachedDescriptor->ReadWrite)
|
||||
{
|
||||
/* Data segment not writeable */
|
||||
Fast486Exception(State, FAST486_EXCEPTION_GP);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the linear address */
|
||||
LinearAddress = CachedDescriptor->Base + Offset;
|
||||
|
||||
/* Write to the linear address */
|
||||
return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Fast486InterruptInternal(PFAST486_STATE State,
|
||||
USHORT SegmentSelector,
|
||||
ULONG Offset,
|
||||
BOOLEAN InterruptGate)
|
||||
{
|
||||
/* Check for protected mode */
|
||||
if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
|
||||
{
|
||||
FAST486_TSS Tss;
|
||||
USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
|
||||
ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
|
||||
|
||||
/* Check if the interrupt handler is more privileged */
|
||||
if (Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
|
||||
{
|
||||
/* Read the TSS */
|
||||
if (!Fast486ReadLinearMemory(State,
|
||||
State->TaskReg.Base,
|
||||
&Tss,
|
||||
sizeof(Tss)))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check the new (higher) privilege level */
|
||||
switch (GET_SEGMENT_RPL(SegmentSelector))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss0))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss1))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss2))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp2;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Should never reach here! */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Push SS selector */
|
||||
if (!Fast486StackPush(State, OldSs)) return FALSE;
|
||||
|
||||
/* Push stack pointer */
|
||||
if (!Fast486StackPush(State, OldEsp)) return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (State->SegmentRegs[FAST486_REG_CS].Size)
|
||||
{
|
||||
/* Set OPSIZE, because INT always pushes 16-bit values in real mode */
|
||||
State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Push EFLAGS */
|
||||
if (!Fast486StackPush(State, State->Flags.Long)) return FALSE;
|
||||
|
||||
/* Push CS selector */
|
||||
if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) return FALSE;
|
||||
|
||||
/* Push the instruction pointer */
|
||||
if (!Fast486StackPush(State, State->InstPtr.Long)) return FALSE;
|
||||
|
||||
if (InterruptGate)
|
||||
{
|
||||
/* Disable interrupts after a jump to an interrupt gate handler */
|
||||
State->Flags.If = FALSE;
|
||||
}
|
||||
|
||||
/* Load new CS */
|
||||
if (!Fast486LoadSegment(State, FAST486_REG_CS, SegmentSelector))
|
||||
{
|
||||
/* An exception occurred during the jump */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (State->SegmentRegs[FAST486_REG_CS].Size)
|
||||
{
|
||||
/* 32-bit code segment, use EIP */
|
||||
State->InstPtr.Long = Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 16-bit code segment, use IP */
|
||||
State->InstPtr.LowWord = LOWORD(Offset);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
Fast486ExceptionWithErrorCode(PFAST486_STATE State,
|
||||
FAST486_EXCEPTIONS ExceptionCode,
|
||||
ULONG ErrorCode)
|
||||
{
|
||||
FAST486_IDT_ENTRY IdtEntry;
|
||||
|
||||
/* Increment the exception count */
|
||||
State->ExceptionCount++;
|
||||
|
||||
/* Check if the exception occurred more than once */
|
||||
if (State->ExceptionCount > 1)
|
||||
{
|
||||
/* Then this is a double fault */
|
||||
ExceptionCode = FAST486_EXCEPTION_DF;
|
||||
}
|
||||
|
||||
/* Check if this is a triple fault */
|
||||
if (State->ExceptionCount == 3)
|
||||
{
|
||||
/* Reset the CPU */
|
||||
Fast486Reset(State);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restore the IP to the saved IP */
|
||||
State->InstPtr = State->SavedInstPtr;
|
||||
|
||||
if (!Fast486GetIntVector(State, ExceptionCode, &IdtEntry))
|
||||
{
|
||||
/*
|
||||
* If this function failed, that means Fast486Exception
|
||||
* was called again, so just return in this case.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perform the interrupt */
|
||||
if (!Fast486InterruptInternal(State,
|
||||
IdtEntry.Selector,
|
||||
MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
|
||||
IdtEntry.Type))
|
||||
{
|
||||
/*
|
||||
* If this function failed, that means Fast486Exception
|
||||
* was called again, so just return in this case.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
|
||||
&& (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
|
||||
{
|
||||
/* Push the error code */
|
||||
if (!Fast486StackPush(State, ErrorCode))
|
||||
{
|
||||
/*
|
||||
* If this function failed, that means Fast486Exception
|
||||
* was called again, so just return in this case.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the exception count */
|
||||
State->ExceptionCount = 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* common.h
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_H_
|
||||
#define _COMMON_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define SIGN_FLAG_BYTE 0x80
|
||||
#define SIGN_FLAG_WORD 0x8000
|
||||
#define SIGN_FLAG_LONG 0x80000000
|
||||
#define REAL_MODE_FLAGS_MASK 0x57FD5
|
||||
#define PROT_MODE_FLAGS_MASK 0x50DD5
|
||||
|
||||
/* Block size for string operations */
|
||||
#define STRING_BLOCK_SIZE 4096
|
||||
|
||||
#define GET_SEGMENT_RPL(s) ((s) & 3)
|
||||
#define GET_SEGMENT_INDEX(s) ((s) & 0xFFF8)
|
||||
#define SEGMENT_TABLE_INDICATOR (1 << 2)
|
||||
#define EXCEPTION_HAS_ERROR_CODE(x) (((x) == 8) || ((x) >= 10 && (x) <= 14))
|
||||
|
||||
#define NO_LOCK_PREFIX()\
|
||||
if (State->PrefixFlags & FAST486_PREFIX_LOCK)\
|
||||
{\
|
||||
Fast486Exception(State, FAST486_EXCEPTION_UD);\
|
||||
return FALSE;\
|
||||
}
|
||||
|
||||
#define TOGGLE_OPSIZE(x)\
|
||||
if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) x = !x;
|
||||
|
||||
#define TOGGLE_ADSIZE(x)\
|
||||
if (State->PrefixFlags & FAST486_PREFIX_ADSIZE) x = !x;
|
||||
|
||||
#define SWAP(x, y) { (x) ^= (y); (y) ^= (x); (x) ^= (y); }
|
||||
|
||||
#define ALIGNMENT_CHECK(x, a) if (State->Flags.Ac \
|
||||
&& (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_AM)\
|
||||
&& (State->Cpl == 3)\
|
||||
&& (((x) % (a)) != 0))\
|
||||
{\
|
||||
Fast486Exception(State, FAST486_EXCEPTION_AC);\
|
||||
return FALSE;\
|
||||
}
|
||||
|
||||
#define PAGE_ALIGN(x) ((x) & 0xFFFFF000)
|
||||
#define PAGE_OFFSET(x) ((x) & 0x00000FFF)
|
||||
#define GET_ADDR_PDE(x) ((x) >> 22)
|
||||
#define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
|
||||
#define INVALID_TLB_FIELD 0xFFFFFFFF
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
typedef struct _FAST486_MOD_REG_RM
|
||||
{
|
||||
FAST486_GEN_REGS Register;
|
||||
BOOLEAN Memory;
|
||||
union
|
||||
{
|
||||
FAST486_GEN_REGS SecondRegister;
|
||||
ULONG MemoryAddress;
|
||||
};
|
||||
} FAST486_MOD_REG_RM, *PFAST486_MOD_REG_RM;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef union _FAST486_PAGE_DIR
|
||||
{
|
||||
struct
|
||||
{
|
||||
ULONG Present : 1;
|
||||
ULONG Writeable : 1;
|
||||
ULONG Usermode : 1;
|
||||
ULONG WriteThrough : 1;
|
||||
ULONG NoCache : 1;
|
||||
ULONG Accessed : 1;
|
||||
ULONG AlwaysZero : 1;
|
||||
ULONG Size : 1;
|
||||
ULONG Unused : 4;
|
||||
ULONG TableAddress : 20;
|
||||
};
|
||||
ULONG Value;
|
||||
} FAST486_PAGE_DIR, *PFAST486_PAGE_DIR;
|
||||
|
||||
C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
|
||||
|
||||
typedef union _FAST486_PAGE_TABLE
|
||||
{
|
||||
struct
|
||||
{
|
||||
ULONG Present : 1;
|
||||
ULONG Writeable : 1;
|
||||
ULONG Usermode : 1;
|
||||
ULONG WriteThrough : 1;
|
||||
ULONG NoCache : 1;
|
||||
ULONG Accessed : 1;
|
||||
ULONG Dirty : 1;
|
||||
ULONG AlwaysZero : 1;
|
||||
ULONG Global : 1;
|
||||
ULONG Unused : 3;
|
||||
ULONG Address : 20;
|
||||
};
|
||||
ULONG Value;
|
||||
} FAST486_PAGE_TABLE, *PFAST486_PAGE_TABLE;
|
||||
|
||||
C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN
|
||||
Fast486ReadMemory
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
FAST486_SEG_REGS SegmentReg,
|
||||
ULONG Offset,
|
||||
BOOLEAN InstFetch,
|
||||
PVOID Buffer,
|
||||
ULONG Size
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
Fast486WriteMemory
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
FAST486_SEG_REGS SegmentReg,
|
||||
ULONG Offset,
|
||||
PVOID Buffer,
|
||||
ULONG Size
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
Fast486InterruptInternal
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
USHORT SegmentSelector,
|
||||
ULONG Offset,
|
||||
BOOLEAN InterruptGate
|
||||
);
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
Fast486ExceptionWithErrorCode
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
FAST486_EXCEPTIONS ExceptionCode,
|
||||
ULONG ErrorCode
|
||||
);
|
||||
|
||||
/* INLINED FUNCTIONS **********************************************************/
|
||||
|
||||
#include "common.inl"
|
||||
|
||||
#endif // _COMMON_H_
|
||||
|
||||
/* EOF */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* extraops.h
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _EXTRAOPS_H_
|
||||
#define _EXTRAOPS_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd);
|
||||
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeExtended);
|
||||
|
||||
#endif // _EXTRAOPS_H_
|
||||
|
||||
/* EOF */
|
||||
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* fast486.c
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <windef.h>
|
||||
|
||||
// #define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#include <fast486.h>
|
||||
#include "common.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FAST486_STEP_INTO,
|
||||
FAST486_STEP_OVER,
|
||||
FAST486_STEP_OUT,
|
||||
FAST486_CONTINUE
|
||||
} FAST486_EXEC_CMD;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static
|
||||
inline
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486ExecutionControl(PFAST486_STATE State, FAST486_EXEC_CMD Command)
|
||||
{
|
||||
UCHAR Opcode;
|
||||
INT ProcedureCallCount = 0;
|
||||
|
||||
/* Main execution loop */
|
||||
do
|
||||
{
|
||||
/* Check if this is a new instruction */
|
||||
if (State->PrefixFlags == 0) State->SavedInstPtr = State->InstPtr;
|
||||
|
||||
/* Perform an instruction fetch */
|
||||
if (!Fast486FetchByte(State, &Opcode))
|
||||
{
|
||||
/* Exception occurred */
|
||||
State->PrefixFlags = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Check for CALL/RET to update ProcedureCallCount.
|
||||
|
||||
if (Fast486OpcodeHandlers[Opcode] != NULL)
|
||||
{
|
||||
/* Call the opcode handler */
|
||||
Fast486OpcodeHandlers[Opcode](State, Opcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is not a valid opcode */
|
||||
Fast486Exception(State, FAST486_EXCEPTION_UD);
|
||||
}
|
||||
|
||||
if (Fast486OpcodeHandlers[Opcode] == Fast486OpcodePrefix)
|
||||
{
|
||||
/* This is a prefix, go to the next instruction immediately */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* A non-prefix opcode has been executed, reset the prefix flags */
|
||||
State->PrefixFlags = 0;
|
||||
|
||||
/*
|
||||
* Check if there is an interrupt to execute, or a hardware interrupt signal
|
||||
* while interrupts are enabled.
|
||||
*/
|
||||
if (State->IntStatus == FAST486_INT_EXECUTE)
|
||||
{
|
||||
FAST486_IDT_ENTRY IdtEntry;
|
||||
|
||||
/* Get the interrupt vector */
|
||||
if (Fast486GetIntVector(State, State->PendingIntNum, &IdtEntry))
|
||||
{
|
||||
/* Perform the interrupt */
|
||||
Fast486InterruptInternal(State,
|
||||
IdtEntry.Selector,
|
||||
MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
|
||||
IdtEntry.Type);
|
||||
|
||||
/* Restore the prefix flags, which would be set to OPSIZE for 32-bit real mode */
|
||||
State->PrefixFlags = 0;
|
||||
}
|
||||
|
||||
/* Clear the interrupt status */
|
||||
State->IntStatus = FAST486_INT_NONE;
|
||||
}
|
||||
else if (State->Flags.If
|
||||
&& (State->IntAckCallback != NULL)
|
||||
&& (State->IntStatus == FAST486_INT_SIGNAL))
|
||||
{
|
||||
/* Acknowledge the interrupt to get the number */
|
||||
State->PendingIntNum = State->IntAckCallback(State);
|
||||
|
||||
/* Set the interrupt status to execute on the next instruction */
|
||||
State->IntStatus = FAST486_INT_EXECUTE;
|
||||
}
|
||||
}
|
||||
while ((Command == FAST486_CONTINUE)
|
||||
|| (Command == FAST486_STEP_OVER && ProcedureCallCount > 0)
|
||||
|| (Command == FAST486_STEP_OUT && ProcedureCallCount >= 0)
|
||||
|| (Fast486OpcodeHandlers[Opcode] == Fast486OpcodePrefix));
|
||||
}
|
||||
|
||||
/* DEFAULT CALLBACKS **********************************************************/
|
||||
|
||||
static VOID
|
||||
NTAPI
|
||||
Fast486MemReadCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
|
||||
RtlMoveMemory(Buffer, (PVOID)Address, Size);
|
||||
}
|
||||
|
||||
static VOID
|
||||
NTAPI
|
||||
Fast486MemWriteCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
|
||||
RtlMoveMemory((PVOID)Address, Buffer, Size);
|
||||
}
|
||||
|
||||
static VOID
|
||||
NTAPI
|
||||
Fast486IoReadCallback(PFAST486_STATE State, ULONG Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
UNREFERENCED_PARAMETER(Port);
|
||||
UNREFERENCED_PARAMETER(Buffer);
|
||||
UNREFERENCED_PARAMETER(DataCount);
|
||||
UNREFERENCED_PARAMETER(DataSize);
|
||||
}
|
||||
|
||||
static VOID
|
||||
NTAPI
|
||||
Fast486IoWriteCallback(PFAST486_STATE State, ULONG Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
UNREFERENCED_PARAMETER(Port);
|
||||
UNREFERENCED_PARAMETER(Buffer);
|
||||
UNREFERENCED_PARAMETER(DataCount);
|
||||
UNREFERENCED_PARAMETER(DataSize);
|
||||
}
|
||||
|
||||
static VOID
|
||||
NTAPI
|
||||
Fast486IdleCallback(PFAST486_STATE State)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
}
|
||||
|
||||
static VOID
|
||||
NTAPI
|
||||
Fast486BopCallback(PFAST486_STATE State, UCHAR BopCode)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
UNREFERENCED_PARAMETER(BopCode);
|
||||
}
|
||||
|
||||
static UCHAR
|
||||
NTAPI
|
||||
Fast486IntAckCallback(PFAST486_STATE State)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
|
||||
/* Return something... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Initialize(PFAST486_STATE State,
|
||||
FAST486_MEM_READ_PROC MemReadCallback,
|
||||
FAST486_MEM_WRITE_PROC MemWriteCallback,
|
||||
FAST486_IO_READ_PROC IoReadCallback,
|
||||
FAST486_IO_WRITE_PROC IoWriteCallback,
|
||||
FAST486_IDLE_PROC IdleCallback,
|
||||
FAST486_BOP_PROC BopCallback,
|
||||
FAST486_INT_ACK_PROC IntAckCallback,
|
||||
PULONG Tlb)
|
||||
{
|
||||
/* Set the callbacks (or use default ones if some are NULL) */
|
||||
State->MemReadCallback = (MemReadCallback ? MemReadCallback : Fast486MemReadCallback );
|
||||
State->MemWriteCallback = (MemWriteCallback ? MemWriteCallback : Fast486MemWriteCallback);
|
||||
State->IoReadCallback = (IoReadCallback ? IoReadCallback : Fast486IoReadCallback );
|
||||
State->IoWriteCallback = (IoWriteCallback ? IoWriteCallback : Fast486IoWriteCallback );
|
||||
State->IdleCallback = (IdleCallback ? IdleCallback : Fast486IdleCallback );
|
||||
State->BopCallback = (BopCallback ? BopCallback : Fast486BopCallback );
|
||||
State->IntAckCallback = (IntAckCallback ? IntAckCallback : Fast486IntAckCallback );
|
||||
|
||||
/* Set the TLB (if given) */
|
||||
State->Tlb = Tlb;
|
||||
|
||||
/* Reset the CPU */
|
||||
Fast486Reset(State);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Reset(PFAST486_STATE State)
|
||||
{
|
||||
FAST486_SEG_REGS i;
|
||||
|
||||
FAST486_MEM_READ_PROC MemReadCallback = State->MemReadCallback;
|
||||
FAST486_MEM_WRITE_PROC MemWriteCallback = State->MemWriteCallback;
|
||||
FAST486_IO_READ_PROC IoReadCallback = State->IoReadCallback;
|
||||
FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
|
||||
FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
|
||||
FAST486_BOP_PROC BopCallback = State->BopCallback;
|
||||
FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
|
||||
PULONG Tlb = State->Tlb;
|
||||
|
||||
/* Clear the entire structure */
|
||||
RtlZeroMemory(State, sizeof(*State));
|
||||
|
||||
/* Initialize the registers */
|
||||
State->Flags.AlwaysSet = 1;
|
||||
State->InstPtr.LowWord = 0xFFF0;
|
||||
|
||||
/* Set the CPL to 0 */
|
||||
State->Cpl = 0;
|
||||
|
||||
/* Initialize segments */
|
||||
for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
|
||||
{
|
||||
State->SegmentRegs[i].Selector = 0;
|
||||
State->SegmentRegs[i].Base = 0;
|
||||
State->SegmentRegs[i].Limit = 0xFFFF;
|
||||
State->SegmentRegs[i].Present = TRUE;
|
||||
State->SegmentRegs[i].ReadWrite = TRUE;
|
||||
State->SegmentRegs[i].Executable = FALSE;
|
||||
State->SegmentRegs[i].DirConf = FALSE;
|
||||
State->SegmentRegs[i].SystemType = 1; // Segment descriptor
|
||||
State->SegmentRegs[i].Dpl = 0;
|
||||
State->SegmentRegs[i].Size = FALSE; // 16-bit
|
||||
}
|
||||
|
||||
/* Initialize the code segment */
|
||||
State->SegmentRegs[FAST486_REG_CS].Executable = TRUE;
|
||||
State->SegmentRegs[FAST486_REG_CS].Selector = 0xF000;
|
||||
State->SegmentRegs[FAST486_REG_CS].Base = 0xFFFF0000;
|
||||
|
||||
/* Initialize the IDT */
|
||||
State->Idtr.Size = 0x3FF;
|
||||
State->Idtr.Address = 0;
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
/* Initialize CR0 */
|
||||
State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
|
||||
#endif
|
||||
|
||||
/* Restore the callbacks and TLB */
|
||||
State->MemReadCallback = MemReadCallback;
|
||||
State->MemWriteCallback = MemWriteCallback;
|
||||
State->IoReadCallback = IoReadCallback;
|
||||
State->IoWriteCallback = IoWriteCallback;
|
||||
State->IdleCallback = IdleCallback;
|
||||
State->BopCallback = BopCallback;
|
||||
State->IntAckCallback = IntAckCallback;
|
||||
State->Tlb = Tlb;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486DumpState(PFAST486_STATE State)
|
||||
{
|
||||
DPRINT1("\nCPU currently executing in %s mode at %04X:%08X\n",
|
||||
(State->ControlRegisters[0] & FAST486_CR0_PE) ? "protected" : "real",
|
||||
State->SegmentRegs[FAST486_REG_CS].Selector,
|
||||
State->InstPtr.Long);
|
||||
DPRINT1("\nGeneral purpose registers:\n"
|
||||
"EAX = %08X\tECX = %08X\tEDX = %08X\tEBX = %08X\n"
|
||||
"ESP = %08X\tEBP = %08X\tESI = %08X\tEDI = %08X\n",
|
||||
State->GeneralRegs[FAST486_REG_EAX].Long,
|
||||
State->GeneralRegs[FAST486_REG_ECX].Long,
|
||||
State->GeneralRegs[FAST486_REG_EDX].Long,
|
||||
State->GeneralRegs[FAST486_REG_EBX].Long,
|
||||
State->GeneralRegs[FAST486_REG_ESP].Long,
|
||||
State->GeneralRegs[FAST486_REG_EBP].Long,
|
||||
State->GeneralRegs[FAST486_REG_ESI].Long,
|
||||
State->GeneralRegs[FAST486_REG_EDI].Long);
|
||||
DPRINT1("\nSegment registers:\n"
|
||||
"ES = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
|
||||
"CS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
|
||||
"SS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
|
||||
"DS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
|
||||
"FS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
|
||||
"GS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n",
|
||||
State->SegmentRegs[FAST486_REG_ES].Selector,
|
||||
State->SegmentRegs[FAST486_REG_ES].Base,
|
||||
State->SegmentRegs[FAST486_REG_ES].Limit,
|
||||
State->SegmentRegs[FAST486_REG_ES].Dpl,
|
||||
State->SegmentRegs[FAST486_REG_CS].Selector,
|
||||
State->SegmentRegs[FAST486_REG_CS].Base,
|
||||
State->SegmentRegs[FAST486_REG_CS].Limit,
|
||||
State->SegmentRegs[FAST486_REG_CS].Dpl,
|
||||
State->SegmentRegs[FAST486_REG_SS].Selector,
|
||||
State->SegmentRegs[FAST486_REG_SS].Base,
|
||||
State->SegmentRegs[FAST486_REG_SS].Limit,
|
||||
State->SegmentRegs[FAST486_REG_SS].Dpl,
|
||||
State->SegmentRegs[FAST486_REG_DS].Selector,
|
||||
State->SegmentRegs[FAST486_REG_DS].Base,
|
||||
State->SegmentRegs[FAST486_REG_DS].Limit,
|
||||
State->SegmentRegs[FAST486_REG_DS].Dpl,
|
||||
State->SegmentRegs[FAST486_REG_FS].Selector,
|
||||
State->SegmentRegs[FAST486_REG_FS].Base,
|
||||
State->SegmentRegs[FAST486_REG_FS].Limit,
|
||||
State->SegmentRegs[FAST486_REG_FS].Dpl,
|
||||
State->SegmentRegs[FAST486_REG_GS].Selector,
|
||||
State->SegmentRegs[FAST486_REG_GS].Base,
|
||||
State->SegmentRegs[FAST486_REG_GS].Limit,
|
||||
State->SegmentRegs[FAST486_REG_GS].Dpl);
|
||||
DPRINT1("\nFlags: %08X (%s %s %s %s %s %s %s %s %s %s %s %s) Iopl: %u\n",
|
||||
State->Flags.Long,
|
||||
State->Flags.Cf ? "CF" : "cf",
|
||||
State->Flags.Pf ? "PF" : "pf",
|
||||
State->Flags.Af ? "AF" : "af",
|
||||
State->Flags.Zf ? "ZF" : "zf",
|
||||
State->Flags.Sf ? "SF" : "sf",
|
||||
State->Flags.Tf ? "TF" : "tf",
|
||||
State->Flags.If ? "IF" : "if",
|
||||
State->Flags.Df ? "DF" : "df",
|
||||
State->Flags.Of ? "OF" : "of",
|
||||
State->Flags.Nt ? "NT" : "nt",
|
||||
State->Flags.Rf ? "RF" : "rf",
|
||||
State->Flags.Vm ? "VM" : "vm",
|
||||
State->Flags.Iopl);
|
||||
DPRINT1("\nControl Registers:\n"
|
||||
"CR0 = %08X\tCR2 = %08X\tCR3 = %08X\n",
|
||||
State->ControlRegisters[FAST486_REG_CR0],
|
||||
State->ControlRegisters[FAST486_REG_CR2],
|
||||
State->ControlRegisters[FAST486_REG_CR3]);
|
||||
DPRINT1("\nDebug Registers:\n"
|
||||
"DR0 = %08X\tDR1 = %08X\tDR2 = %08X\n"
|
||||
"DR3 = %08X\tDR4 = %08X\tDR5 = %08X\n",
|
||||
State->DebugRegisters[FAST486_REG_DR0],
|
||||
State->DebugRegisters[FAST486_REG_DR1],
|
||||
State->DebugRegisters[FAST486_REG_DR2],
|
||||
State->DebugRegisters[FAST486_REG_DR3],
|
||||
State->DebugRegisters[FAST486_REG_DR4],
|
||||
State->DebugRegisters[FAST486_REG_DR5]);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Continue(PFAST486_STATE State)
|
||||
{
|
||||
/* Call the internal function */
|
||||
Fast486ExecutionControl(State, FAST486_CONTINUE);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486StepInto(PFAST486_STATE State)
|
||||
{
|
||||
/* Call the internal function */
|
||||
Fast486ExecutionControl(State, FAST486_STEP_INTO);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486StepOver(PFAST486_STATE State)
|
||||
{
|
||||
/* Call the internal function */
|
||||
Fast486ExecutionControl(State, FAST486_STEP_OVER);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486StepOut(PFAST486_STATE State)
|
||||
{
|
||||
/* Call the internal function */
|
||||
Fast486ExecutionControl(State, FAST486_STEP_OUT);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486Interrupt(PFAST486_STATE State, UCHAR Number)
|
||||
{
|
||||
/* Set the interrupt status and the number */
|
||||
State->IntStatus = FAST486_INT_EXECUTE;
|
||||
State->PendingIntNum = Number;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486InterruptSignal(PFAST486_STATE State)
|
||||
{
|
||||
/* Set the interrupt status */
|
||||
State->IntStatus = FAST486_INT_SIGNAL;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
|
||||
{
|
||||
/* Load the new CS */
|
||||
if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
|
||||
{
|
||||
/* An exception occurred, let the handler execute instead */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the new IP */
|
||||
State->InstPtr.Long = Offset;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486SetStack(PFAST486_STATE State, USHORT Segment, ULONG Offset)
|
||||
{
|
||||
/* Load the new SS */
|
||||
if (!Fast486LoadSegment(State, FAST486_REG_SS, Segment))
|
||||
{
|
||||
/* An exception occurred, let the handler execute instead */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the new SP */
|
||||
State->GeneralRegs[FAST486_REG_ESP].Long = Offset;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
Fast486SetSegment(PFAST486_STATE State,
|
||||
FAST486_SEG_REGS Segment,
|
||||
USHORT Selector)
|
||||
{
|
||||
/* Call the internal function */
|
||||
Fast486LoadSegment(State, Segment, Selector);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* fpu.c
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <windef.h>
|
||||
|
||||
// #define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#include <fast486.h>
|
||||
#include "common.h"
|
||||
#include "opcodes.h"
|
||||
#include "fpu.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF)
|
||||
{
|
||||
FAST486_MOD_REG_RM ModRegRm;
|
||||
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
|
||||
|
||||
/* Get the operands */
|
||||
if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
|
||||
{
|
||||
/* Exception occurred */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FPU_CHECK();
|
||||
|
||||
#ifndef FAST486_NO_FPU
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
|
||||
return FALSE;
|
||||
#else
|
||||
/* Do nothing */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* fpu.h
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _FPU_H_
|
||||
#define _FPU_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define FPU_CHECK() if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_EM) \
|
||||
{ \
|
||||
Fast486Exception(State, FAST486_EXCEPTION_NM); \
|
||||
return FALSE; \
|
||||
}
|
||||
#define FPU_ST(i) State->FpuRegisters[(State->FpuStatus.Top + (i)) % FAST486_NUM_FPU_REGS]
|
||||
|
||||
enum
|
||||
{
|
||||
FPU_SINGLE_PRECISION = 0,
|
||||
FPU_DOUBLE_PRECISION = 2,
|
||||
FPU_DOUBLE_EXT_PRECISION = 3
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FPU_TAG_VALID = 0,
|
||||
FPU_TAG_ZERO = 1,
|
||||
FPU_TAG_SPECIAL = 2,
|
||||
FPU_TAG_EMPTY = 3
|
||||
};
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8);
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9);
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA);
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB);
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC);
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD);
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE);
|
||||
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF);
|
||||
|
||||
#endif // _FPU_H_
|
||||
|
||||
/* EOF */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* opcodes.h
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _OPCODES_H_
|
||||
#define _OPCODES_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define FAST486_NUM_OPCODE_HANDLERS 256
|
||||
#define FAST486_OPCODE_WRITE_REG (1 << 1)
|
||||
#define FAST486_OPCODE_HANDLER(x) \
|
||||
BOOLEAN FASTCALL x(PFAST486_STATE State, UCHAR Opcode)
|
||||
|
||||
typedef BOOLEAN (FASTCALL *FAST486_OPCODE_HANDLER_PROC)(PFAST486_STATE, UCHAR);
|
||||
|
||||
extern
|
||||
FAST486_OPCODE_HANDLER_PROC
|
||||
Fast486OpcodeHandlers[FAST486_NUM_OPCODE_HANDLERS];
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePrefix);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushReg);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePopReg);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeNop);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeHalt);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeInByte);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeIn);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeOut);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushEs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePopEs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushCs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushSs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePopSs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushDs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePopDs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeDaa);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeDas);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAaa);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAas);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushAll);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePopAll);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeBound);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeArpl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushImm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeLea);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCwde);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCdq);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeWait);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSahf);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeLahf);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeRet);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeEnter);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeLeave);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeRetFarImm);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeInt);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeIret);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAam);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeAad);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeXlat);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeLoop);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCall);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeJmp);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeSalc);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeMovs);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeCmps);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeStos);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeLods);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeScas);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeIns);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeOuts);
|
||||
|
||||
#endif // _OPCODES_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Fast486 386/486 CPU Emulation Library
|
||||
* opgroups.h
|
||||
*
|
||||
* Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _OPGROUPS_H_
|
||||
#define _OPGROUPS_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9);
|
||||
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA);
|
||||
|
||||
#endif // _OPGROUPS_H_
|
||||
|
||||
/* EOF */
|
||||
|
||||
@@ -280,7 +280,14 @@ l_ReadHeaderFromFile:
|
||||
nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
|
||||
|
||||
if(!NT_SUCCESS(nStatus))
|
||||
DIE(("ReadFile failed, status %08X\n", nStatus));
|
||||
{
|
||||
NTSTATUS ReturnedStatus = nStatus;
|
||||
|
||||
/* If it attempted to read past the end of the file, it means e_lfanew is invalid */
|
||||
if (ReturnedStatus == STATUS_END_OF_FILE) nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
|
||||
|
||||
DIE(("ReadFile failed, status %08X\n", ReturnedStatus));
|
||||
}
|
||||
|
||||
ASSERT(pData);
|
||||
ASSERT(pBuffer);
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
|
||||
if(ARCH STREQUAL "i386")
|
||||
add_subdirectory(ntvdm)
|
||||
endif()
|
||||
add_subdirectory(ntvdm)
|
||||
add_subdirectory(win)
|
||||
add_subdirectory(win32)
|
||||
|
||||
@@ -1,11 +1,42 @@
|
||||
|
||||
include_directories(.)
|
||||
include_directories(
|
||||
${REACTOS_SOURCE_DIR}/include/reactos/libs/fast486
|
||||
ntvdm)
|
||||
|
||||
add_executable(ntvdm
|
||||
spec2def(ntvdm.exe ntvdm.spec)
|
||||
|
||||
list(APPEND SOURCE
|
||||
bios/bios32/bios32.c
|
||||
bios/bios32/kbdbios32.c
|
||||
bios/bios32/vidbios32.c
|
||||
bios/bios.c
|
||||
bios/kbdbios.c
|
||||
bios/rom.c
|
||||
bios/vidbios.c
|
||||
hardware/cmos.c
|
||||
hardware/pic.c
|
||||
hardware/ps2.c
|
||||
hardware/speaker.c
|
||||
hardware/timer.c
|
||||
hardware/vga.c
|
||||
dos/dos32krnl/bios.c
|
||||
dos/dos32krnl/dos.c
|
||||
dos/dem.c
|
||||
bop.c
|
||||
callback.c
|
||||
clock.c
|
||||
emulator.c
|
||||
io.c
|
||||
registers.c
|
||||
utils.c
|
||||
vddsup.c
|
||||
ntvdm.c
|
||||
ntvdm.rc)
|
||||
ntvdm.rc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ntvdm.def)
|
||||
|
||||
set_module_type(ntvdm win32cui)
|
||||
add_importlibs(ntvdm ntdll user32 gdi32 advapi32 msvcrt kernel32)
|
||||
add_dependencies(ntvdm ndk bugcodes)
|
||||
add_executable(ntvdm ${SOURCE})
|
||||
set_module_type(ntvdm win32cui UNICODE)
|
||||
set_image_base(ntvdm 0x0F000000)
|
||||
target_link_libraries(ntvdm fast486)
|
||||
add_importlibs(ntvdm user32 gdi32 advapi32 msvcrt kernel32 ntdll)
|
||||
add_cd_file(TARGET ntvdm DESTINATION reactos/system32 FOR all)
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: bios.c
|
||||
* PURPOSE: VDM BIOS Support Library
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
#include "bop.h"
|
||||
|
||||
#include "bios.h"
|
||||
#include "bios32/bios32.h"
|
||||
|
||||
#include "rom.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "hardware/cmos.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define BOP_BIOSINIT 0x00 // Windows NTVDM (SoftPC) BIOS calls BOP 0x00
|
||||
// to let the virtual machine initialize itself
|
||||
// the IVT and its hardware.
|
||||
#define BOP_EQUIPLIST 0x11
|
||||
#define BOP_GETMEMSIZE 0x12
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BOOLEAN Bios32Loaded = FALSE;
|
||||
|
||||
static CALLBACK16 __BiosContext;
|
||||
PBIOS_DATA_AREA Bda;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID WINAPI BiosInitBop(LPWORD Stack)
|
||||
{
|
||||
BOOLEAN Success;
|
||||
|
||||
/* Load the second part of the Windows NTVDM BIOS image */
|
||||
LPCSTR BiosFileName = "bios1.rom";
|
||||
PVOID BiosLocation = (PVOID)TO_LINEAR(BIOS_SEGMENT, 0x0000);
|
||||
DWORD BiosSize = 0;
|
||||
|
||||
/* Disable interrupts */
|
||||
setIF(0);
|
||||
|
||||
DisplayMessage(L"You are loading Windows NTVDM BIOS!\n");
|
||||
|
||||
/* Initialize a private callback context */
|
||||
InitializeContext(&__BiosContext, BIOS_SEGMENT, 0x0000);
|
||||
|
||||
Success = LoadRom(BiosFileName, BiosLocation, &BiosSize);
|
||||
DPRINT1("BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
if (Success == FALSE)
|
||||
{
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
// DisplayMessage(L"First bytes at 0x%p: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n"
|
||||
// L"3 last bytes at 0x%p: 0x%02x 0x%02x 0x%02x",
|
||||
// BiosLocation,
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 0),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 1),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 2),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 3),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 4),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 5),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 6),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 7),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 8),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 9),
|
||||
|
||||
// (PVOID)((ULONG_PTR)BiosLocation + BiosSize - 2),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 2),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 1),
|
||||
// *(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 0));
|
||||
|
||||
/* Initialize IVT and hardware */
|
||||
|
||||
/* Initialize the Keyboard and Video BIOS */
|
||||
if (!KbdBiosInitialize() || !VidBiosInitialize())
|
||||
{
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load VGA BIOS */
|
||||
// Success = LoadRom("v7vga.rom", (PVOID)0xC0000, &BiosSize);
|
||||
// DPRINT1("VGA BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
/* Enable interrupts */
|
||||
setIF(1);
|
||||
|
||||
///////////// MUST BE DONE AFTER IVT INITIALIZATION !! /////////////////////
|
||||
|
||||
/* Load some ROMs */
|
||||
// Success = LoadRom("boot.bin", (PVOID)0xE0000, &BiosSize);
|
||||
// DPRINT1("Test ROM loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
SearchAndInitRoms(&__BiosContext);
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID WINAPI BiosEquipmentService(LPWORD Stack)
|
||||
{
|
||||
/* Return the equipment list */
|
||||
setAX(Bda->EquipmentList);
|
||||
}
|
||||
|
||||
VOID WINAPI BiosGetMemorySize(LPWORD Stack)
|
||||
{
|
||||
/* Return the conventional memory size in kB, typically 640 kB */
|
||||
setAX(Bda->MemorySize);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
BiosInitialize(IN LPCSTR BiosFileName)
|
||||
{
|
||||
BOOLEAN Success = FALSE;
|
||||
|
||||
/* Disable interrupts */
|
||||
setIF(0);
|
||||
|
||||
/* Initialize the BDA pointer */
|
||||
Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0);
|
||||
|
||||
/* Register the BIOS support BOPs */
|
||||
RegisterBop(BOP_BIOSINIT , BiosInitBop);
|
||||
RegisterBop(BOP_EQUIPLIST , BiosEquipmentService);
|
||||
RegisterBop(BOP_GETMEMSIZE, BiosGetMemorySize);
|
||||
|
||||
if (BiosFileName)
|
||||
{
|
||||
PVOID BiosLocation = NULL;
|
||||
DWORD BiosSize = 0;
|
||||
|
||||
Success = LoadBios(BiosFileName, &BiosLocation, &BiosSize);
|
||||
DPRINT1("BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
if (!Success) return FALSE;
|
||||
|
||||
DisplayMessage(L"First bytes at 0x%p: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n"
|
||||
L"3 last bytes at 0x%p: 0x%02x 0x%02x 0x%02x",
|
||||
BiosLocation,
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 0),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 1),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 2),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 3),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 4),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 5),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 6),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 7),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 8),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + 9),
|
||||
|
||||
(PVOID)((ULONG_PTR)BiosLocation + BiosSize - 2),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 2),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 1),
|
||||
*(PCHAR)((ULONG_PTR)REAL_TO_PHYS(BiosLocation) + BiosSize - 0));
|
||||
|
||||
DisplayMessage(L"POST at 0x%p: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
|
||||
TO_LINEAR(getCS(), getIP()),
|
||||
*(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 0),
|
||||
*(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 1),
|
||||
*(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 2),
|
||||
*(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 3),
|
||||
*(PCHAR)((ULONG_PTR)SEG_OFF_TO_PTR(getCS(), getIP()) + 4));
|
||||
|
||||
/* Boot it up */
|
||||
|
||||
/*
|
||||
* The CPU is already in reset-mode so that
|
||||
* CS:IP points to F000:FFF0 as required.
|
||||
*/
|
||||
DisplayMessage(L"CS=0x%p ; IP=0x%p", getCS(), getIP());
|
||||
// setCS(0xF000);
|
||||
// setIP(0xFFF0);
|
||||
|
||||
Success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Success = Bios32Loaded = Bios32Initialize();
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
setIF(1);
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
VOID
|
||||
BiosCleanup(VOID)
|
||||
{
|
||||
if (Bios32Loaded) Bios32Cleanup();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: bios.h
|
||||
* PURPOSE: VDM BIOS Support Library
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _BIOS_H_
|
||||
#define _BIOS_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
#include "kbdbios.h"
|
||||
#include "vidbios.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define BDA_SEGMENT 0x40
|
||||
#define BIOS_SEGMENT 0xF000
|
||||
|
||||
#define BIOS_EQUIPMENT_LIST 0x2C // HACK: Disable FPU for now
|
||||
|
||||
/*
|
||||
* BIOS Data Area at 0040:XXXX
|
||||
*
|
||||
* See: http://webpages.charter.net/danrollins/techhelp/0093.HTM
|
||||
* and: http://www.bioscentral.com/misc/bda.htm
|
||||
* for more information.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
WORD SerialPorts[4]; // 0x00
|
||||
WORD ParallelPorts[3]; // 0x08
|
||||
WORD EbdaSegment; // 0x0e - ParallelPort in PC/XT
|
||||
WORD EquipmentList; // 0x10
|
||||
BYTE Reserved0; // 0x12 - Errors in PCjr infrared keyboard link
|
||||
WORD MemorySize; // 0x13
|
||||
WORD Reserved1; // 0x15 - Scratch pad for manufacturing error tests
|
||||
WORD KeybdShiftFlags; // 0x17
|
||||
BYTE AlternateKeypad; // 0x19
|
||||
WORD KeybdBufferHead; // 0x1a
|
||||
WORD KeybdBufferTail; // 0x1c
|
||||
WORD KeybdBuffer[BIOS_KBD_BUFFER_SIZE]; // 0x1e
|
||||
BYTE DriveRecalibrate; // 0x3e
|
||||
BYTE DriveMotorStatus; // 0x3f
|
||||
BYTE MotorShutdownCounter; // 0x40
|
||||
BYTE LastDisketteOperation; // 0x41
|
||||
BYTE Reserved2[7]; // 0x42
|
||||
BYTE VideoMode; // 0x49
|
||||
WORD ScreenColumns; // 0x4a
|
||||
WORD VideoPageSize; // 0x4c
|
||||
WORD VideoPageOffset; // 0x4e
|
||||
WORD CursorPosition[BIOS_MAX_PAGES]; // 0x50
|
||||
BYTE CursorEndLine; // 0x60
|
||||
BYTE CursorStartLine; // 0x61
|
||||
BYTE VideoPage; // 0x62
|
||||
WORD CrtBasePort; // 0x63
|
||||
BYTE CrtModeControl; // 0x65
|
||||
BYTE CrtColorPaletteMask; // 0x66
|
||||
BYTE CassetteData[5]; // 0x67
|
||||
DWORD TickCounter; // 0x6c
|
||||
BYTE MidnightPassed; // 0x70
|
||||
BYTE BreakFlag; // 0x71
|
||||
WORD SoftReset; // 0x72
|
||||
BYTE LastDiskOperation; // 0x74
|
||||
BYTE NumDisks; // 0x75
|
||||
BYTE DriveControlByte; // 0x76
|
||||
BYTE DiskPortOffset; // 0x77
|
||||
BYTE LptTimeOut[4]; // 0x78
|
||||
BYTE ComTimeOut[4]; // 0x7c
|
||||
WORD KeybdBufferStart; // 0x80
|
||||
WORD KeybdBufferEnd; // 0x82
|
||||
BYTE ScreenRows; // 0x84
|
||||
WORD CharacterHeight; // 0x85
|
||||
BYTE EGAFlags[2]; // 0x87
|
||||
BYTE VGAFlags[2]; // 0x89
|
||||
DWORD Reserved3; // 0x8b
|
||||
BYTE Reserved4; // 0x8f
|
||||
BYTE Reserved5[2]; // 0x90
|
||||
BYTE Reserved6[2]; // 0x92
|
||||
BYTE Reserved7[2]; // 0x94
|
||||
WORD Reserved8; // 0x96
|
||||
DWORD Reserved9; // 0x98
|
||||
DWORD Reserved10; // 0x9c
|
||||
DWORD Reserved11[2]; // 0xa0
|
||||
DWORD EGAPtr; // 0xa8
|
||||
BYTE Reserved12[68]; // 0xac
|
||||
BYTE Reserved13[16]; // 0xf0
|
||||
|
||||
DWORD Reserved14; // 0x100
|
||||
BYTE Reserved15[12]; // 0x104
|
||||
BYTE Reserved16[17]; // 0x110
|
||||
BYTE Reserved17[15]; // 0x121
|
||||
BYTE Reserved18[3]; // 0x130
|
||||
} BIOS_DATA_AREA, *PBIOS_DATA_AREA;
|
||||
#pragma pack(pop)
|
||||
|
||||
C_ASSERT(sizeof(BIOS_DATA_AREA) == 0x133);
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
extern PBIOS_DATA_AREA Bda;
|
||||
|
||||
VOID WINAPI BiosEquipmentService(LPWORD Stack);
|
||||
VOID WINAPI BiosGetMemorySize(LPWORD Stack);
|
||||
|
||||
BOOLEAN
|
||||
BiosInitialize(IN LPCSTR BiosFileName);
|
||||
|
||||
VOID
|
||||
BiosCleanup(VOID);
|
||||
|
||||
#endif // _BIOS_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: bios32.c
|
||||
* PURPOSE: VDM 32-bit BIOS
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
#include "bop.h"
|
||||
|
||||
#include "../bios.h"
|
||||
#include "../rom.h"
|
||||
#include "bios32.h"
|
||||
#include "bios32p.h"
|
||||
#include "kbdbios32.h"
|
||||
#include "vidbios32.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "hardware/cmos.h"
|
||||
#include "hardware/pic.h"
|
||||
#include "hardware/timer.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
CALLBACK16 BiosContext;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID WINAPI BiosException(LPWORD Stack)
|
||||
{
|
||||
/* Get the exception number and call the emulator API */
|
||||
BYTE ExceptionNumber = LOBYTE(Stack[STACK_INT_NUM]);
|
||||
EmulatorException(ExceptionNumber, Stack);
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosMiscService(LPWORD Stack)
|
||||
{
|
||||
switch (getAH())
|
||||
{
|
||||
/* Wait */
|
||||
case 0x86:
|
||||
{
|
||||
/*
|
||||
* Interval in microseconds in CX:DX
|
||||
* See Ralf Brown: http://www.ctyme.com/intr/rb-1525.htm
|
||||
* for more information.
|
||||
*/
|
||||
Sleep(MAKELONG(getDX(), getCX()));
|
||||
|
||||
/* Clear CF */
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy Extended Memory */
|
||||
case 0x87:
|
||||
{
|
||||
DWORD Count = (DWORD)getCX() * 2;
|
||||
PFAST486_GDT_ENTRY Gdt = (PFAST486_GDT_ENTRY)SEG_OFF_TO_PTR(getES(), getSI());
|
||||
DWORD SourceBase = Gdt[2].Base + (Gdt[2].BaseMid << 16) + (Gdt[2].BaseHigh << 24);
|
||||
DWORD SourceLimit = Gdt[2].Limit + (Gdt[2].LimitHigh << 16);
|
||||
DWORD DestBase = Gdt[3].Base + (Gdt[3].BaseMid << 16) + (Gdt[3].BaseHigh << 24);
|
||||
DWORD DestLimit = Gdt[3].Limit + (Gdt[3].LimitHigh << 16);
|
||||
|
||||
/* Check for flags */
|
||||
if (Gdt[2].Granularity) SourceLimit = (SourceLimit << 12) | 0xFFF;
|
||||
if (Gdt[3].Granularity) DestLimit = (DestLimit << 12) | 0xFFF;
|
||||
|
||||
if ((Count > SourceLimit) || (Count > DestLimit))
|
||||
{
|
||||
setAX(0x80);
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy */
|
||||
RtlMoveMemory((PVOID)((ULONG_PTR)BaseAddress + DestBase),
|
||||
(PVOID)((ULONG_PTR)BaseAddress + SourceBase),
|
||||
Count);
|
||||
|
||||
setAX(ERROR_SUCCESS);
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get Extended Memory Size */
|
||||
case 0x88:
|
||||
{
|
||||
UCHAR Low, High;
|
||||
|
||||
/*
|
||||
* Return the (usable) extended memory (after 1 MB)
|
||||
* size in kB from CMOS.
|
||||
*/
|
||||
IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_LOW);
|
||||
Low = IOReadB(CMOS_DATA_PORT);
|
||||
IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_ACTUAL_EXT_MEMORY_HIGH);
|
||||
High = IOReadB(CMOS_DATA_PORT);
|
||||
setAX(MAKEWORD(Low, High));
|
||||
|
||||
/* Clear CF */
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
|
||||
getAH());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosTimeService(LPWORD Stack)
|
||||
{
|
||||
switch (getAH())
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
/* Set AL to 1 if midnight had passed, 0 otherwise */
|
||||
setAL(Bda->MidnightPassed ? 0x01 : 0x00);
|
||||
|
||||
/* Return the tick count in CX:DX */
|
||||
setCX(HIWORD(Bda->TickCounter));
|
||||
setDX(LOWORD(Bda->TickCounter));
|
||||
|
||||
/* Reset the midnight flag */
|
||||
Bda->MidnightPassed = FALSE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
{
|
||||
/* Set the tick count to CX:DX */
|
||||
Bda->TickCounter = MAKELONG(getDX(), getCX());
|
||||
|
||||
/* Reset the midnight flag */
|
||||
Bda->MidnightPassed = FALSE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
|
||||
getAH());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
|
||||
{
|
||||
/* Increase the system tick count */
|
||||
Bda->TickCounter++;
|
||||
}
|
||||
|
||||
|
||||
// From SeaBIOS
|
||||
static VOID PicSetIRQMask(USHORT off, USHORT on)
|
||||
{
|
||||
UCHAR pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8;
|
||||
IOWriteB(PIC_MASTER_DATA, (IOReadB(PIC_MASTER_DATA) & ~pic1off) | pic1on);
|
||||
IOWriteB(PIC_SLAVE_DATA , (IOReadB(PIC_SLAVE_DATA ) & ~pic2off) | pic2on);
|
||||
}
|
||||
|
||||
// From SeaBIOS
|
||||
VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func)
|
||||
{
|
||||
UCHAR vector;
|
||||
|
||||
PicSetIRQMask(1 << hwirq, 0);
|
||||
if (hwirq < 8)
|
||||
vector = BIOS_PIC_MASTER_INT + hwirq;
|
||||
else
|
||||
vector = BIOS_PIC_SLAVE_INT + hwirq - 8;
|
||||
|
||||
RegisterBiosInt32(vector, func);
|
||||
}
|
||||
|
||||
|
||||
VOID PicIRQComplete(LPWORD Stack)
|
||||
{
|
||||
/* Get the interrupt number */
|
||||
BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]);
|
||||
|
||||
/*
|
||||
* If this was a PIC IRQ, send an End-of-Interrupt to the PIC.
|
||||
*/
|
||||
|
||||
if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8)
|
||||
{
|
||||
/* It was an IRQ from the master PIC */
|
||||
IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
|
||||
}
|
||||
else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8)
|
||||
{
|
||||
/* It was an IRQ from the slave PIC */
|
||||
IOWriteB(PIC_SLAVE_CMD , PIC_OCW2_EOI);
|
||||
IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
|
||||
}
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosHandleMasterPicIRQ(LPWORD Stack)
|
||||
{
|
||||
BYTE IrqNumber;
|
||||
|
||||
IOWriteB(PIC_MASTER_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
|
||||
IrqNumber = IOReadB(PIC_MASTER_CMD);
|
||||
|
||||
DPRINT("Master - IrqNumber = 0x%x\n", IrqNumber);
|
||||
|
||||
PicIRQComplete(Stack);
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosHandleSlavePicIRQ(LPWORD Stack)
|
||||
{
|
||||
BYTE IrqNumber;
|
||||
|
||||
IOWriteB(PIC_SLAVE_CMD, PIC_OCW3_READ_ISR /* == 0x0B */);
|
||||
IrqNumber = IOReadB(PIC_SLAVE_CMD);
|
||||
|
||||
DPRINT("Slave - IrqNumber = 0x%x\n", IrqNumber);
|
||||
|
||||
PicIRQComplete(Stack);
|
||||
}
|
||||
|
||||
// Timer IRQ 0
|
||||
static VOID WINAPI BiosTimerIrq(LPWORD Stack)
|
||||
{
|
||||
/*
|
||||
* Perform the system timer interrupt.
|
||||
*
|
||||
* Do not call directly BiosSystemTimerInterrupt(Stack);
|
||||
* because some programs may hook only BIOS_SYS_TIMER_INTERRUPT
|
||||
* for their purpose...
|
||||
*/
|
||||
/** EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT); **/
|
||||
Int32Call(&BiosContext, BIOS_SYS_TIMER_INTERRUPT);
|
||||
PicIRQComplete(Stack);
|
||||
}
|
||||
|
||||
|
||||
static VOID BiosHwSetup(VOID)
|
||||
{
|
||||
/* Initialize the master and the slave PICs (cascade mode) */
|
||||
IOWriteB(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
|
||||
IOWriteB(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4);
|
||||
|
||||
/*
|
||||
* Set the interrupt vector offsets for each PIC
|
||||
* (base IRQs: 0x08-0x0F for IRQ 0-7, 0x70-0x77 for IRQ 8-15)
|
||||
*/
|
||||
IOWriteB(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
|
||||
IOWriteB(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT );
|
||||
|
||||
/* Tell the master PIC that there is a slave PIC at IRQ 2 */
|
||||
IOWriteB(PIC_MASTER_DATA, 1 << 2);
|
||||
/* Tell the slave PIC its cascade identity */
|
||||
IOWriteB(PIC_SLAVE_DATA , 2);
|
||||
|
||||
/* Make sure both PICs are in 8086 mode */
|
||||
IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086);
|
||||
IOWriteB(PIC_SLAVE_DATA , PIC_ICW4_8086);
|
||||
|
||||
/* Clear the masks for both PICs */
|
||||
// IOWriteB(PIC_MASTER_DATA, 0x00);
|
||||
// IOWriteB(PIC_SLAVE_DATA , 0x00);
|
||||
/* Disable all IRQs */
|
||||
IOWriteB(PIC_MASTER_DATA, 0xFF);
|
||||
IOWriteB(PIC_SLAVE_DATA , 0xFF);
|
||||
|
||||
|
||||
/* Initialize PIT Counter 0 */
|
||||
IOWriteB(PIT_COMMAND_PORT, 0x34);
|
||||
IOWriteB(PIT_DATA_PORT(0), 0x00);
|
||||
IOWriteB(PIT_DATA_PORT(0), 0x00);
|
||||
|
||||
/* Initialize PIT Counter 1 */
|
||||
IOWriteB(PIT_COMMAND_PORT, 0x74);
|
||||
IOWriteB(PIT_DATA_PORT(1), 0x00);
|
||||
IOWriteB(PIT_DATA_PORT(1), 0x00);
|
||||
|
||||
/* Initialize PIT Counter 2 */
|
||||
IOWriteB(PIT_COMMAND_PORT, 0xB4);
|
||||
IOWriteB(PIT_DATA_PORT(2), 0x00);
|
||||
IOWriteB(PIT_DATA_PORT(2), 0x00);
|
||||
|
||||
EnableHwIRQ(0, BiosTimerIrq);
|
||||
}
|
||||
|
||||
static VOID InitializeBiosInt32(VOID)
|
||||
{
|
||||
USHORT i;
|
||||
// USHORT Offset = 0;
|
||||
|
||||
/* Initialize the callback context */
|
||||
InitializeContext(&BiosContext, BIOS_SEGMENT, 0x0000);
|
||||
|
||||
/* Register the BIOS 32-bit Interrupts */
|
||||
for (i = 0x00; i <= 0xFF; i++)
|
||||
{
|
||||
// Offset += RegisterInt32(MAKELONG(Offset, BIOS_SEGMENT), i, NULL, NULL);
|
||||
BiosContext.NextOffset += RegisterInt32(MAKELONG(BiosContext.NextOffset,
|
||||
BiosContext.Segment),
|
||||
i, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Initialize the exception vector interrupts to a default Exception handler */
|
||||
for (i = 0; i < 8; i++)
|
||||
RegisterBiosInt32(i, BiosException);
|
||||
|
||||
/* Initialize HW vector interrupts to a default HW handler */
|
||||
for (i = BIOS_PIC_MASTER_INT; i < BIOS_PIC_MASTER_INT + 8; i++)
|
||||
RegisterBiosInt32(i, BiosHandleMasterPicIRQ);
|
||||
for (i = BIOS_PIC_SLAVE_INT ; i < BIOS_PIC_SLAVE_INT + 8; i++)
|
||||
RegisterBiosInt32(i, BiosHandleSlavePicIRQ);
|
||||
|
||||
/* Initialize software vector handlers */
|
||||
RegisterBiosInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService );
|
||||
RegisterBiosInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize );
|
||||
RegisterBiosInt32(BIOS_MISC_INTERRUPT , BiosMiscService );
|
||||
RegisterBiosInt32(BIOS_TIME_INTERRUPT , BiosTimeService );
|
||||
RegisterBiosInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt);
|
||||
|
||||
/* Some interrupts are in fact addresses to tables */
|
||||
((PULONG)BaseAddress)[0x1E] = (ULONG)NULL;
|
||||
((PULONG)BaseAddress)[0x41] = (ULONG)NULL;
|
||||
((PULONG)BaseAddress)[0x46] = (ULONG)NULL;
|
||||
((PULONG)BaseAddress)[0x48] = (ULONG)NULL;
|
||||
((PULONG)BaseAddress)[0x49] = (ULONG)NULL;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
/*
|
||||
* The BIOS POST (Power On-Self Test)
|
||||
*/
|
||||
BOOLEAN Bios32Initialize(VOID)
|
||||
{
|
||||
BOOLEAN Success;
|
||||
UCHAR Low, High;
|
||||
|
||||
/* Initialize the stack */
|
||||
// That's what says IBM... (stack at 30:00FF going downwards)
|
||||
// setSS(0x0000);
|
||||
// setSP(0x0400);
|
||||
setSS(0x0050); // Stack at 50:0400, going downwards
|
||||
setSP(0x0400);
|
||||
|
||||
/* Set data segment */
|
||||
setDS(BDA_SEGMENT);
|
||||
|
||||
/* Initialize the BDA contents */
|
||||
Bda->EquipmentList = BIOS_EQUIPMENT_LIST;
|
||||
|
||||
/*
|
||||
* Retrieve the conventional memory size
|
||||
* in kB from CMOS, typically 640 kB.
|
||||
*/
|
||||
IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_LOW);
|
||||
Low = IOReadB(CMOS_DATA_PORT);
|
||||
IOWriteB(CMOS_ADDRESS_PORT, CMOS_REG_BASE_MEMORY_HIGH);
|
||||
High = IOReadB(CMOS_DATA_PORT);
|
||||
Bda->MemorySize = MAKEWORD(Low, High);
|
||||
|
||||
/* Register the BIOS 32-bit Interrupts */
|
||||
InitializeBiosInt32();
|
||||
|
||||
/* Initialize platform hardware (PIC/PIT chips, ...) */
|
||||
BiosHwSetup();
|
||||
|
||||
/* Initialize the Keyboard and Video BIOS */
|
||||
if (!KbdBios32Initialize() || !VidBios32Initialize()) return FALSE;
|
||||
|
||||
///////////// MUST BE DONE AFTER IVT INITIALIZATION !! /////////////////////
|
||||
|
||||
/* Load some ROMs */
|
||||
Success = LoadRom("boot.bin", (PVOID)0xE0000, NULL);
|
||||
DPRINT1("Test ROM loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
SearchAndInitRoms(&BiosContext);
|
||||
|
||||
/* We are done */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID Bios32Cleanup(VOID)
|
||||
{
|
||||
VidBios32Cleanup();
|
||||
KbdBios32Cleanup();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: bios32.h
|
||||
* PURPOSE: VDM 32-bit BIOS
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _BIOS32_H_
|
||||
#define _BIOS32_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
// #include "../bios.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
// #define BIOS_EQUIPMENT_INTERRUPT 0x11
|
||||
// #define BIOS_MEMORY_SIZE 0x12
|
||||
// #define BIOS_MISC_INTERRUPT 0x15
|
||||
// #define BIOS_TIME_INTERRUPT 0x1A
|
||||
// #define BIOS_SYS_TIMER_INTERRUPT 0x1C
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN Bios32Initialize(VOID);
|
||||
VOID Bios32Cleanup(VOID);
|
||||
|
||||
#endif // _BIOS32_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: bios32.h
|
||||
* PURPOSE: VDM 32-bit BIOS
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _BIOS32P_H_
|
||||
#define _BIOS32P_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
#include "../bios.h"
|
||||
|
||||
/**/ #include "callback.h" /**/
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define BIOS_PIC_MASTER_INT 0x08
|
||||
#define BIOS_PIC_SLAVE_INT 0x70
|
||||
|
||||
#define BIOS_EQUIPMENT_INTERRUPT 0x11
|
||||
#define BIOS_MEMORY_SIZE 0x12
|
||||
#define BIOS_MISC_INTERRUPT 0x15
|
||||
#define BIOS_TIME_INTERRUPT 0x1A
|
||||
#define BIOS_SYS_TIMER_INTERRUPT 0x1C
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
extern CALLBACK16 BiosContext;
|
||||
#define RegisterBiosInt32(IntNumber, IntHandler) \
|
||||
do { \
|
||||
BiosContext.NextOffset += RegisterInt32(MAKELONG(BiosContext.NextOffset, \
|
||||
BiosContext.Segment), \
|
||||
(IntNumber), (IntHandler), NULL); \
|
||||
} while(0);
|
||||
|
||||
VOID EnableHwIRQ(UCHAR hwirq, EMULATOR_INT32_PROC func);
|
||||
VOID PicIRQComplete(LPWORD Stack);
|
||||
|
||||
#endif // _BIOS32P_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: kbdbios32.c
|
||||
* PURPOSE: VDM Keyboard 32-bit BIOS
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
|
||||
#include "kbdbios32.h"
|
||||
#include "../kbdbios.h"
|
||||
#include "bios32p.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "hardware/ps2.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BYTE BiosKeyboardMap[256];
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static BOOLEAN BiosKbdBufferPush(WORD Data)
|
||||
{
|
||||
/* Get the location of the element after the tail */
|
||||
WORD NextElement = Bda->KeybdBufferTail + sizeof(WORD);
|
||||
|
||||
/* Wrap it around if it's at or beyond the end */
|
||||
if (NextElement >= Bda->KeybdBufferEnd) NextElement = Bda->KeybdBufferStart;
|
||||
|
||||
/* If it's full, fail */
|
||||
if (NextElement == Bda->KeybdBufferHead) return FALSE;
|
||||
|
||||
/* Put the value in the queue */
|
||||
*((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferTail)) = Data;
|
||||
Bda->KeybdBufferTail += sizeof(WORD);
|
||||
|
||||
/* Check if we are at, or have passed, the end of the buffer */
|
||||
if (Bda->KeybdBufferTail >= Bda->KeybdBufferEnd)
|
||||
{
|
||||
/* Return it to the beginning */
|
||||
Bda->KeybdBufferTail = Bda->KeybdBufferStart;
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN BiosKbdBufferTop(LPWORD Data)
|
||||
{
|
||||
/* If it's empty, fail */
|
||||
if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE;
|
||||
|
||||
/* Otherwise, get the value and return success */
|
||||
*Data = *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferHead));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN BiosKbdBufferPop(VOID)
|
||||
{
|
||||
/* If it's empty, fail */
|
||||
if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE;
|
||||
|
||||
/* Remove the value from the queue */
|
||||
Bda->KeybdBufferHead += sizeof(WORD);
|
||||
|
||||
/* Check if we are at, or have passed, the end of the buffer */
|
||||
if (Bda->KeybdBufferHead >= Bda->KeybdBufferEnd)
|
||||
{
|
||||
/* Return it to the beginning */
|
||||
Bda->KeybdBufferHead = Bda->KeybdBufferStart;
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static WORD BiosPeekCharacter(VOID)
|
||||
{
|
||||
WORD CharacterData = 0;
|
||||
|
||||
/* Get the key from the queue, but don't remove it */
|
||||
if (BiosKbdBufferTop(&CharacterData)) return CharacterData;
|
||||
else return 0xFFFF;
|
||||
}
|
||||
|
||||
WORD BiosGetCharacter(VOID)
|
||||
{
|
||||
WORD CharacterData = 0;
|
||||
|
||||
/* Check if there is a key available */
|
||||
if (BiosKbdBufferTop(&CharacterData))
|
||||
{
|
||||
/* A key was available, remove it from the queue */
|
||||
BiosKbdBufferPop();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No key available. Set the handler CF to repeat the BOP */
|
||||
setCF(1);
|
||||
// CharacterData = 0xFFFF;
|
||||
}
|
||||
|
||||
return CharacterData;
|
||||
}
|
||||
|
||||
static VOID WINAPI BiosKeyboardService(LPWORD Stack)
|
||||
{
|
||||
switch (getAH())
|
||||
{
|
||||
/* Wait for keystroke and read */
|
||||
case 0x00:
|
||||
/* Wait for extended keystroke and read */
|
||||
case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
|
||||
{
|
||||
/* Read the character (and wait if necessary) */
|
||||
setAX(BiosGetCharacter());
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get keystroke status */
|
||||
case 0x01:
|
||||
/* Get extended keystroke status */
|
||||
case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
|
||||
{
|
||||
WORD Data = BiosPeekCharacter();
|
||||
|
||||
if (Data != 0xFFFF)
|
||||
{
|
||||
/* There is a character, clear ZF and return it */
|
||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
|
||||
setAX(Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No character, set ZF */
|
||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get shift status */
|
||||
case 0x02:
|
||||
{
|
||||
/* Return the lower byte of the keyboard shift status word */
|
||||
setAL(LOBYTE(Bda->KeybdShiftFlags));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reserved */
|
||||
case 0x04:
|
||||
{
|
||||
DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Push keystroke */
|
||||
case 0x05:
|
||||
{
|
||||
/* Return 0 if success, 1 if failure */
|
||||
setAL(BiosKbdBufferPush(getCX()) == FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get extended shift status */
|
||||
case 0x12:
|
||||
{
|
||||
/*
|
||||
* Be careful! The returned word is similar to Bda->KeybdShiftFlags
|
||||
* but the high byte is organized differently:
|
||||
* the bytes 2 and 3 of the high byte are not the same...
|
||||
*/
|
||||
WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF);
|
||||
|
||||
/* Return the extended keyboard shift status word */
|
||||
setAX(KeybdShiftFlags);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
|
||||
getAH());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard IRQ 1
|
||||
static VOID WINAPI BiosKeyboardIrq(LPWORD Stack)
|
||||
{
|
||||
BYTE ScanCode, VirtualKey;
|
||||
WORD Character;
|
||||
|
||||
/* Get the scan code and virtual key code */
|
||||
ScanCode = IOReadB(PS2_DATA_PORT);
|
||||
VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
|
||||
|
||||
/* Check if this is a key press or release */
|
||||
if (!(ScanCode & (1 << 7)))
|
||||
{
|
||||
/* Key press */
|
||||
if (VirtualKey == VK_NUMLOCK ||
|
||||
VirtualKey == VK_CAPITAL ||
|
||||
VirtualKey == VK_SCROLL ||
|
||||
VirtualKey == VK_INSERT)
|
||||
{
|
||||
/* For toggle keys, toggle the lowest bit in the keyboard map */
|
||||
BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
|
||||
}
|
||||
|
||||
/* Set the highest bit */
|
||||
BiosKeyboardMap[VirtualKey] |= (1 << 7);
|
||||
|
||||
/* Find out which character this is */
|
||||
Character = 0;
|
||||
if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0)
|
||||
{
|
||||
/* Not ASCII */
|
||||
Character = 0;
|
||||
}
|
||||
|
||||
/* Push it onto the BIOS keyboard queue */
|
||||
BiosKbdBufferPush(MAKEWORD(Character, ScanCode));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Key release, unset the highest bit */
|
||||
BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
|
||||
}
|
||||
|
||||
/* Clear the keyboard flags */
|
||||
Bda->KeybdShiftFlags = 0;
|
||||
|
||||
/* Set the appropriate flags based on the state */
|
||||
if (BiosKeyboardMap[VK_RSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RSHIFT;
|
||||
if (BiosKeyboardMap[VK_LSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT;
|
||||
if (BiosKeyboardMap[VK_CONTROL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CTRL;
|
||||
if (BiosKeyboardMap[VK_MENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_ALT;
|
||||
if (BiosKeyboardMap[VK_SCROLL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL_ON;
|
||||
if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK_ON;
|
||||
if (BiosKeyboardMap[VK_CAPITAL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK_ON;
|
||||
if (BiosKeyboardMap[VK_INSERT] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT_ON;
|
||||
if (BiosKeyboardMap[VK_RMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RALT;
|
||||
if (BiosKeyboardMap[VK_LMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LALT;
|
||||
if (BiosKeyboardMap[VK_SNAPSHOT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SYSRQ;
|
||||
if (BiosKeyboardMap[VK_PAUSE] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_PAUSE;
|
||||
if (BiosKeyboardMap[VK_SCROLL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL;
|
||||
if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK;
|
||||
if (BiosKeyboardMap[VK_CAPITAL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK;
|
||||
if (BiosKeyboardMap[VK_INSERT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT;
|
||||
|
||||
PicIRQComplete(Stack);
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN KbdBios32Initialize(VOID)
|
||||
{
|
||||
/* Initialize the common Keyboard BIOS Support Library */
|
||||
if (!KbdBiosInitialize()) return FALSE;
|
||||
|
||||
/* Initialize the BDA */
|
||||
Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer);
|
||||
Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD);
|
||||
Bda->KeybdBufferHead = Bda->KeybdBufferTail = 0;
|
||||
|
||||
/* Register the BIOS 32-bit Interrupts */
|
||||
|
||||
/* Initialize software vector handlers */
|
||||
RegisterBiosInt32(BIOS_KBD_INTERRUPT, BiosKeyboardService);
|
||||
|
||||
/* Set up the HW vector interrupts */
|
||||
EnableHwIRQ(1, BiosKeyboardIrq);
|
||||
// EnableHwIRQ(12, BiosMouseIrq);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID KbdBios32Cleanup(VOID)
|
||||
{
|
||||
/* Cleanup the common Keyboard BIOS Support Library */
|
||||
KbdBiosCleanup();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: kbdbios32.h
|
||||
* PURPOSE: VDM Keyboard 32-bit BIOS
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _KBDBIOS32_H_
|
||||
#define _KBDBIOS32_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
// #define BIOS_KBD_INTERRUPT 0x16
|
||||
|
||||
#define BIOS_KBD_BUFFER_SIZE 16
|
||||
|
||||
#define BDA_KBDFLAG_RSHIFT (1 << 0)
|
||||
#define BDA_KBDFLAG_LSHIFT (1 << 1)
|
||||
#define BDA_KBDFLAG_CTRL (1 << 2)
|
||||
#define BDA_KBDFLAG_ALT (1 << 3)
|
||||
#define BDA_KBDFLAG_SCROLL_ON (1 << 4)
|
||||
#define BDA_KBDFLAG_NUMLOCK_ON (1 << 5)
|
||||
#define BDA_KBDFLAG_CAPSLOCK_ON (1 << 6)
|
||||
#define BDA_KBDFLAG_INSERT_ON (1 << 7)
|
||||
#define BDA_KBDFLAG_RALT (1 << 8)
|
||||
#define BDA_KBDFLAG_LALT (1 << 9)
|
||||
#define BDA_KBDFLAG_SYSRQ (1 << 10)
|
||||
#define BDA_KBDFLAG_PAUSE (1 << 11)
|
||||
#define BDA_KBDFLAG_SCROLL (1 << 12)
|
||||
#define BDA_KBDFLAG_NUMLOCK (1 << 13)
|
||||
#define BDA_KBDFLAG_CAPSLOCK (1 << 14)
|
||||
#define BDA_KBDFLAG_INSERT (1 << 15)
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN KbdBios32Initialize(VOID);
|
||||
VOID KbdBios32Cleanup(VOID);
|
||||
|
||||
#endif // _KBDBIOS32_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: vidbios32.c
|
||||
* PURPOSE: VDM Video 32-bit BIOS
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*
|
||||
* NOTE: All of the real code is in bios/vidbios.c
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
|
||||
#include "vidbios32.h"
|
||||
#include "../vidbios.h"
|
||||
#include "bios32p.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN VidBios32Initialize(VOID)
|
||||
{
|
||||
/* Initialize the common Video BIOS Support Library */
|
||||
if (!VidBiosInitialize()) return FALSE;
|
||||
|
||||
/* Register the BIOS 32-bit Interrupts */
|
||||
RegisterBiosInt32(BIOS_VIDEO_INTERRUPT, VidBiosVideoService);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID VidBios32Cleanup(VOID)
|
||||
{
|
||||
/* Cleanup the common Video BIOS Support Library */
|
||||
VidBiosCleanup();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: vidbios32.h
|
||||
* PURPOSE: VDM Video 32-bit BIOS
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*
|
||||
* NOTE: All of the real code is in bios/vidbios.c
|
||||
*/
|
||||
|
||||
#ifndef _VIDBIOS32_H_
|
||||
#define _VIDBIOS32_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
// #define BIOS_VIDEO_INTERRUPT 0x10
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN VidBios32Initialize(VOID);
|
||||
VOID VidBios32Cleanup(VOID);
|
||||
|
||||
#endif // _VIDBIOS32_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: kbdbios.c
|
||||
* PURPOSE: VDM Keyboard BIOS Support Library
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
#include "bop.h"
|
||||
|
||||
#include "bios.h"
|
||||
// #include "kbdbios.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define BOP_KBD_IRQ 0x09
|
||||
#define BOP_KBD_INT 0x16
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
static VOID WINAPI KbdBiosIRQ(LPWORD Stack)
|
||||
{
|
||||
DPRINT1("KbdBiosIRQ is UNIMPLEMENTED\n");
|
||||
}
|
||||
|
||||
static VOID WINAPI KbdBiosINT(LPWORD Stack)
|
||||
{
|
||||
DPRINT1("KbdBiosINT is UNIMPLEMENTED\n");
|
||||
}
|
||||
|
||||
BOOLEAN KbdBiosInitialize(VOID)
|
||||
{
|
||||
/* Register the BIOS support BOPs */
|
||||
RegisterBop(BOP_KBD_IRQ, KbdBiosIRQ);
|
||||
RegisterBop(BOP_KBD_INT, KbdBiosINT);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID KbdBiosCleanup(VOID)
|
||||
{
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: kbdbios.h
|
||||
* PURPOSE: VDM Keyboard BIOS Support Library
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _KBDBIOS_H_
|
||||
#define _KBDBIOS_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define BIOS_KBD_INTERRUPT 0x16
|
||||
|
||||
#define BIOS_KBD_BUFFER_SIZE 16
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
WORD BiosGetCharacter(VOID);
|
||||
|
||||
BOOLEAN KbdBiosInitialize(VOID);
|
||||
VOID KbdBiosCleanup(VOID);
|
||||
|
||||
#endif // _KBDBIOS_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: rom.c
|
||||
* PURPOSE: ROM Support Functions
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "rom.h"
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static HANDLE
|
||||
OpenRomFile(IN PCSTR RomFileName,
|
||||
OUT PULONG RomSize OPTIONAL)
|
||||
{
|
||||
HANDLE hRomFile;
|
||||
ULONG ulRomSize = 0;
|
||||
|
||||
/* Open the ROM image file */
|
||||
hRomFile = FileOpen(RomFileName, &ulRomSize);
|
||||
|
||||
/* If we failed, bail out */
|
||||
if (hRomFile == NULL) return NULL;
|
||||
|
||||
/*
|
||||
* The size of the ROM image file is at most 256kB. For instance,
|
||||
* the SeaBIOS image, which includes also expansion ROMs inside it,
|
||||
* covers the range C000:0000 to F000:FFFF .
|
||||
*/
|
||||
if (ulRomSize > 0x40000)
|
||||
{
|
||||
/* We failed, bail out */
|
||||
DPRINT1("ROM image size 0x%lx too large, expected at most 0x40000 (256kB)", ulRomSize);
|
||||
FileClose(hRomFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Success, return file handle and size if needed */
|
||||
if (RomSize) *RomSize = ulRomSize;
|
||||
return hRomFile;
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
LoadRomFileByHandle(IN HANDLE RomFileHandle,
|
||||
IN PVOID RomLocation,
|
||||
IN ULONG RomSize,
|
||||
OUT PULONG BytesRead)
|
||||
{
|
||||
/*
|
||||
* The size of the ROM image file is at most 256kB. For instance,
|
||||
* the SeaBIOS image, which includes also expansion ROMs inside it,
|
||||
* covers the range C000:0000 to F000:FFFF .
|
||||
*/
|
||||
if (RomSize > 0x40000)
|
||||
{
|
||||
DPRINT1("ROM image size 0x%lx too large, expected at most 0x40000 (256kB)", RomSize);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Attempt to load the ROM image file into memory */
|
||||
return FileLoadByHandle(RomFileHandle,
|
||||
REAL_TO_PHYS(RomLocation),
|
||||
RomSize,
|
||||
BytesRead);
|
||||
}
|
||||
|
||||
static UCHAR
|
||||
ComputeChecksum(IN ULONG RomLocation,
|
||||
IN ULONG RomSize)
|
||||
{
|
||||
ULONG RomLastAddress = RomLocation + RomSize;
|
||||
UCHAR Sum = 0x00; // Using a UCHAR guarantees that we wrap at 0xFF i.e. we do a sum modulo 0x100.
|
||||
|
||||
while (RomLocation < RomLastAddress)
|
||||
{
|
||||
Sum += *(PUCHAR)REAL_TO_PHYS(RomLocation);
|
||||
++RomLocation;
|
||||
}
|
||||
|
||||
return Sum;
|
||||
}
|
||||
|
||||
static VOID
|
||||
InitRomRange(IN PCALLBACK16 Context,
|
||||
IN ULONG Start,
|
||||
IN ULONG End,
|
||||
IN ULONG Increment)
|
||||
{
|
||||
ULONG Address, AddressBoot;
|
||||
ULONG RomSize;
|
||||
UCHAR Checksum;
|
||||
|
||||
for (Address = Start; Address < End; Address += Increment)
|
||||
{
|
||||
/* Does the ROM have a valid signature? */
|
||||
if (*(PUSHORT)REAL_TO_PHYS(Address) == OPTION_ROM_SIGNATURE)
|
||||
{
|
||||
/* Check the control sum of the ROM */
|
||||
|
||||
/*
|
||||
* If this is an adapter ROM (Start: C8000, End: E0000), its
|
||||
* reported size is stored in byte 2 of the ROM.
|
||||
*
|
||||
* If this is an expansion ROM (Start: E0000, End: F0000),
|
||||
* its real length is 64kB.
|
||||
*/
|
||||
RomSize = *(PUCHAR)REAL_TO_PHYS(Address + 2) * 512;
|
||||
if (Address >= 0xE0000) RomSize = 0x10000;
|
||||
|
||||
Checksum = ComputeChecksum(Address, RomSize);
|
||||
if (Checksum == 0x00)
|
||||
{
|
||||
AddressBoot = Address + 3;
|
||||
DPRINT1("Going to run @ address 0x%p\n", AddressBoot);
|
||||
|
||||
AddressBoot = MAKELONG((AddressBoot & 0xFFFF), (AddressBoot & 0xF0000) >> 4);
|
||||
// setDS((Address & 0xF0000) >> 4);
|
||||
setDS((Address & 0xFF000) >> 4);
|
||||
RunCallback16(Context, AddressBoot);
|
||||
// Call16((AddressBoot & 0xF0000) >> 4, (AddressBoot & 0xFFFF));
|
||||
|
||||
DPRINT1("Rom @ address 0x%p initialized\n", Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("Rom @ address 0x%p has invalid checksum of 0x%02x\n", Address, Checksum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN
|
||||
LoadBios(IN PCSTR BiosFileName,
|
||||
OUT PVOID* BiosLocation OPTIONAL,
|
||||
OUT PULONG BiosSize OPTIONAL)
|
||||
{
|
||||
BOOLEAN Success;
|
||||
HANDLE hBiosFile;
|
||||
ULONG ulBiosSize = 0;
|
||||
PVOID pBiosLocation;
|
||||
|
||||
/* Open the BIOS image file */
|
||||
hBiosFile = OpenRomFile(BiosFileName, &ulBiosSize);
|
||||
|
||||
/* If we failed, bail out */
|
||||
if (hBiosFile == NULL) return FALSE;
|
||||
|
||||
/* BIOS location needs to be aligned on 32-bit boundary */
|
||||
// (PVOID)((ULONG_PTR)BaseAddress + ROM_AREA_END + 1 - ulBiosSize)
|
||||
pBiosLocation = MEM_ALIGN_DOWN(TO_LINEAR(0xF000, 0xFFFF) + 1 - ulBiosSize, sizeof(ULONG));
|
||||
|
||||
/* Attempt to load the BIOS image file into memory */
|
||||
Success = LoadRomFileByHandle(hBiosFile,
|
||||
pBiosLocation,
|
||||
ulBiosSize,
|
||||
&ulBiosSize);
|
||||
DPRINT1("BIOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
/* Close the BIOS image file */
|
||||
FileClose(hBiosFile);
|
||||
|
||||
/* In case of success, return BIOS location and size if needed */
|
||||
if (Success)
|
||||
{
|
||||
if (BiosLocation) *BiosLocation = pBiosLocation;
|
||||
if (BiosSize) *BiosSize = ulBiosSize;
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
LoadRom(IN PCSTR RomFileName,
|
||||
IN PVOID RomLocation,
|
||||
OUT PULONG RomSize OPTIONAL)
|
||||
{
|
||||
BOOLEAN Success;
|
||||
HANDLE hRomFile;
|
||||
ULONG ulRomSize = 0;
|
||||
|
||||
/* Open the ROM image file */
|
||||
hRomFile = OpenRomFile(RomFileName, &ulRomSize);
|
||||
|
||||
/* If we failed, bail out */
|
||||
if (hRomFile == NULL) return FALSE;
|
||||
|
||||
/* Attempt to load the ROM image file into memory */
|
||||
Success = LoadRomFileByHandle(hRomFile,
|
||||
RomLocation,
|
||||
ulRomSize,
|
||||
&ulRomSize);
|
||||
DPRINT1("ROM loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
/* Close the ROM image file and return */
|
||||
FileClose(hRomFile);
|
||||
|
||||
/* In case of success, return ROM size if needed */
|
||||
if (Success)
|
||||
{
|
||||
if (RomSize) *RomSize = ulRomSize;
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
VOID
|
||||
SearchAndInitRoms(IN PCALLBACK16 Context)
|
||||
{
|
||||
/* Adapters ROMs -- Start: C8000, End: E0000, 2kB blocks */
|
||||
InitRomRange(Context, 0xC8000, 0xE0000, 0x0800);
|
||||
|
||||
/* Expansion ROM -- Start: E0000, End: F0000, 64kB block */
|
||||
InitRomRange(Context, 0xE0000, 0xEFFFF, 0x10000);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: rom.h
|
||||
* PURPOSE: ROM Support Functions
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _ROM_H_
|
||||
#define _ROM_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define ROM_AREA_START 0xE0000
|
||||
#define ROM_AREA_END 0xFFFFF
|
||||
|
||||
#define OPTION_ROM_SIGNATURE 0xAA55
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN
|
||||
LoadBios(IN PCSTR BiosFileName,
|
||||
OUT PVOID* BiosLocation OPTIONAL,
|
||||
OUT PULONG BiosSize OPTIONAL);
|
||||
|
||||
BOOLEAN
|
||||
LoadRom(IN PCSTR RomFileName,
|
||||
IN PVOID RomLocation,
|
||||
OUT PULONG RomSize OPTIONAL);
|
||||
|
||||
VOID
|
||||
SearchAndInitRoms(IN PCALLBACK16 Context);
|
||||
|
||||
#endif // _ROM_H_
|
||||
|
||||
/* EOF */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: vidbios.h
|
||||
* PURPOSE: VDM Video BIOS Support Library
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _VIDBIOS_H_
|
||||
#define _VIDBIOS_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define BIOS_VIDEO_INTERRUPT 0x10
|
||||
|
||||
#define CONSOLE_FONT_HEIGHT 8
|
||||
#define BIOS_DEFAULT_VIDEO_MODE 0x03
|
||||
#define BIOS_MAX_PAGES 8
|
||||
#define BIOS_MAX_VIDEO_MODE 0x13
|
||||
#define DEFAULT_ATTRIBUTE 0x07
|
||||
|
||||
#define GRAPHICS_VIDEO_SEG 0xA000
|
||||
#define TEXT_VIDEO_SEG 0xB800
|
||||
|
||||
enum
|
||||
{
|
||||
SCROLL_DIRECTION_UP,
|
||||
SCROLL_DIRECTION_DOWN,
|
||||
SCROLL_DIRECTION_LEFT,
|
||||
SCROLL_DIRECTION_RIGHT
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID WINAPI VidBiosVideoService(LPWORD Stack);
|
||||
|
||||
VOID VidBiosSyncCursorPosition(VOID);
|
||||
|
||||
BOOLEAN VidBiosInitialize(VOID);
|
||||
VOID VidBiosCleanup(VOID);
|
||||
|
||||
#endif // _VIDBIOS_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: bop.c
|
||||
* PURPOSE: BIOS Operation Handlers
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
// #define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "bop.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
/*
|
||||
* This is the list of registered BOP handlers.
|
||||
*/
|
||||
EMULATOR_BOP_PROC BopProc[EMULATOR_MAX_BOP_NUM] = { NULL };
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID RegisterBop(BYTE BopCode, EMULATOR_BOP_PROC BopHandler)
|
||||
{
|
||||
BopProc[BopCode] = BopHandler;
|
||||
}
|
||||
|
||||
VOID WINAPI EmulatorBiosOperation(PFAST486_STATE State, UCHAR BopCode)
|
||||
{
|
||||
WORD StackSegment, StackPointer;
|
||||
LPWORD Stack;
|
||||
|
||||
/* Get the SS:SP */
|
||||
StackSegment = State->SegmentRegs[FAST486_REG_SS].Selector;
|
||||
StackPointer = State->GeneralRegs[FAST486_REG_ESP].LowWord;
|
||||
|
||||
/* Get the stack */
|
||||
Stack = (LPWORD)SEG_OFF_TO_PTR(StackSegment, StackPointer);
|
||||
|
||||
/* Call the BOP handler */
|
||||
if (BopProc[BopCode] != NULL)
|
||||
BopProc[BopCode](Stack);
|
||||
else
|
||||
DPRINT("Invalid BOP code: 0x%02X\n", BopCode);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: bop.h
|
||||
* PURPOSE: BIOS Operation Handlers
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _BOP_H_
|
||||
#define _BOP_H_
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define EMULATOR_BOP 0xC4C4
|
||||
#define EMULATOR_MAX_BOP_NUM 0xFF + 1
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
typedef VOID (WINAPI *EMULATOR_BOP_PROC)(LPWORD Stack);
|
||||
|
||||
VOID RegisterBop(BYTE BopCode, EMULATOR_BOP_PROC BopHandler);
|
||||
VOID WINAPI EmulatorBiosOperation(PFAST486_STATE State, UCHAR BopCode);
|
||||
|
||||
#endif // _BOP_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: callback.c
|
||||
* PURPOSE: 16 and 32-bit Callbacks Support
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
|
||||
#include "bop.h"
|
||||
#include <isvbop.h>
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
/*
|
||||
* This is the list of registered 32-bit Interrupt handlers.
|
||||
*/
|
||||
EMULATOR_INT32_PROC Int32Proc[EMULATOR_MAX_INT32_NUM] = { NULL };
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define BOP_CONTROL 0xFF // Control BOP Handler
|
||||
#define BOP_CONTROL_DEFFUNC 0x00 // Default Control BOP Function
|
||||
|
||||
/* 32-bit Interrupt dispatcher function code for the Control BOP Handler */
|
||||
#define BOP_CONTROL_INT32 0xFF
|
||||
|
||||
|
||||
#define BOP(num) LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), (num)
|
||||
#define UnSimulate16(trap) \
|
||||
do { \
|
||||
*(PUSHORT)(trap) = EMULATOR_BOP; \
|
||||
(trap) += sizeof(USHORT); \
|
||||
*(trap) = BOP_UNSIMULATE; \
|
||||
} while(0)
|
||||
// #define UnSimulate16 MAKELONG(EMULATOR_BOP, BOP_UNSIMULATE) // BOP(BOP_UNSIMULATE)
|
||||
|
||||
#define CALL16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
|
||||
#define INT16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
|
||||
|
||||
/* 16-bit generic interrupt code for calling a 32-bit interrupt handler */
|
||||
BYTE Int16To32[] =
|
||||
{
|
||||
0xFA, // cli
|
||||
|
||||
/* Push the value of the interrupt to be called */
|
||||
0x6A, 0xFF, // push i (patchable to 0x6A, 0xIntNum)
|
||||
|
||||
/* The counter variable (initialized to 0) */
|
||||
0x6A, 0x00, // push 0
|
||||
|
||||
/* Stack variables */
|
||||
0x83, 0xEC, 0x04, // sub sp, 4
|
||||
|
||||
/* The BOP Sequence */
|
||||
// BOP_SEQ:
|
||||
0xF8, // clc
|
||||
BOP(BOP_CONTROL), // Control BOP
|
||||
BOP_CONTROL_INT32, // 32-bit Interrupt dispatcher
|
||||
|
||||
0x73, 0x04, // jnc EXIT (offset +4)
|
||||
|
||||
0xFB, // sti
|
||||
|
||||
// HACK: The following instruction should be HLT!
|
||||
0x90, // nop
|
||||
|
||||
0xEB, 0xF5, // jmp BOP_SEQ (offset -11)
|
||||
|
||||
// EXIT:
|
||||
0x83, 0xC4, 0x08, // add sp, 8
|
||||
0xCF, // iret
|
||||
};
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID
|
||||
InitializeContext(IN PCALLBACK16 Context,
|
||||
IN USHORT Segment,
|
||||
IN USHORT Offset)
|
||||
{
|
||||
Context->TrampolineFarPtr = MAKELONG(Offset, Segment);
|
||||
Context->Segment = Segment;
|
||||
Context->NextOffset = Offset + max(CALL16_TRAMPOLINE_SIZE,
|
||||
INT16_TRAMPOLINE_SIZE);
|
||||
}
|
||||
|
||||
VOID
|
||||
Call16(IN USHORT Segment,
|
||||
IN USHORT Offset)
|
||||
{
|
||||
/* Save CS:IP */
|
||||
USHORT OrgCS = getCS();
|
||||
USHORT OrgIP = getIP();
|
||||
|
||||
/* Set the new CS:IP */
|
||||
setCS(Segment);
|
||||
setIP(Offset);
|
||||
|
||||
DPRINT("Call16(%04X:%04X)\n", Segment, Offset);
|
||||
|
||||
/* Start CPU simulation */
|
||||
EmulatorSimulate();
|
||||
|
||||
/* Restore CS:IP */
|
||||
setCS(OrgCS);
|
||||
setIP(OrgIP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
RegisterCallback16(IN ULONG FarPtr,
|
||||
IN LPBYTE CallbackCode,
|
||||
IN SIZE_T CallbackSize,
|
||||
OUT PSIZE_T CodeSize OPTIONAL)
|
||||
{
|
||||
LPBYTE CodeStart = (LPBYTE)FAR_POINTER(FarPtr);
|
||||
LPBYTE Code = CodeStart;
|
||||
|
||||
SIZE_T OurCodeSize = CallbackSize;
|
||||
|
||||
if (CallbackCode == NULL) CallbackSize = 0;
|
||||
|
||||
if (CallbackCode)
|
||||
{
|
||||
/* 16-bit interrupt code */
|
||||
RtlCopyMemory(Code, CallbackCode, CallbackSize);
|
||||
Code += CallbackSize;
|
||||
}
|
||||
|
||||
/* Return the real size of the code if needed */
|
||||
if (CodeSize) *CodeSize = OurCodeSize; // == (ULONG_PTR)Code - (ULONG_PTR)CodeStart;
|
||||
|
||||
// /* Return the entry-point address for 32-bit calls */
|
||||
// return (ULONG_PTR)(CodeStart + CallbackSize);
|
||||
return OurCodeSize;
|
||||
}
|
||||
|
||||
VOID
|
||||
RunCallback16(IN PCALLBACK16 Context,
|
||||
IN ULONG FarPtr)
|
||||
{
|
||||
PUCHAR TrampolineBase = (PUCHAR)FAR_POINTER(Context->TrampolineFarPtr);
|
||||
PUCHAR Trampoline = TrampolineBase;
|
||||
UCHAR OldTrampoline[CALL16_TRAMPOLINE_SIZE];
|
||||
|
||||
/* Save the old trampoline */
|
||||
((PULONGLONG)&OldTrampoline)[0] = ((PULONGLONG)TrampolineBase)[0];
|
||||
|
||||
DPRINT1("RunCallback16(0x%p)\n", FarPtr);
|
||||
|
||||
/* Build the generic entry-point for 16-bit far calls */
|
||||
*Trampoline++ = 0x9A; // Call far seg:off
|
||||
*(PULONG)Trampoline = FarPtr;
|
||||
Trampoline += sizeof(ULONG);
|
||||
UnSimulate16(Trampoline);
|
||||
|
||||
/* Perform the call */
|
||||
Call16(HIWORD(Context->TrampolineFarPtr),
|
||||
LOWORD(Context->TrampolineFarPtr));
|
||||
|
||||
/* Restore the old trampoline */
|
||||
((PULONGLONG)TrampolineBase)[0] = ((PULONGLONG)&OldTrampoline)[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
RegisterInt16(IN ULONG FarPtr,
|
||||
IN BYTE IntNumber,
|
||||
IN LPBYTE CallbackCode,
|
||||
IN SIZE_T CallbackSize,
|
||||
OUT PSIZE_T CodeSize OPTIONAL)
|
||||
{
|
||||
/* Get a pointer to the IVT and set the corresponding entry (far pointer) */
|
||||
LPDWORD IntVecTable = (LPDWORD)SEG_OFF_TO_PTR(0x0000, 0x0000);
|
||||
IntVecTable[IntNumber] = FarPtr;
|
||||
|
||||
/* Register the 16-bit callback */
|
||||
return RegisterCallback16(FarPtr,
|
||||
CallbackCode,
|
||||
CallbackSize,
|
||||
CodeSize);
|
||||
}
|
||||
|
||||
ULONG
|
||||
RegisterInt32(IN ULONG FarPtr,
|
||||
IN BYTE IntNumber,
|
||||
IN EMULATOR_INT32_PROC IntHandler,
|
||||
OUT PSIZE_T CodeSize OPTIONAL)
|
||||
{
|
||||
/* Array for holding our copy of the 16-bit interrupt callback */
|
||||
BYTE IntCallback[sizeof(Int16To32)/sizeof(BYTE)];
|
||||
|
||||
/* Check whether the 32-bit interrupt was already registered */
|
||||
// if (Int32Proc[IntNumber] != NULL)
|
||||
// {
|
||||
// DPRINT1("RegisterInt32: Interrupt 0x%X already registered!\n", IntNumber);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
/* Register the 32-bit interrupt handler */
|
||||
Int32Proc[IntNumber] = IntHandler;
|
||||
|
||||
/* Copy the generic 16-bit interrupt callback and patch it */
|
||||
RtlCopyMemory(IntCallback, Int16To32, sizeof(Int16To32));
|
||||
IntCallback[2] = IntNumber;
|
||||
|
||||
/* Register the 16-bit interrupt callback */
|
||||
return RegisterInt16(FarPtr,
|
||||
IntNumber,
|
||||
IntCallback,
|
||||
sizeof(IntCallback),
|
||||
CodeSize);
|
||||
}
|
||||
|
||||
VOID
|
||||
Int32Call(IN PCALLBACK16 Context,
|
||||
IN BYTE IntNumber)
|
||||
{
|
||||
PUCHAR TrampolineBase = (PUCHAR)FAR_POINTER(Context->TrampolineFarPtr);
|
||||
PUCHAR Trampoline = TrampolineBase;
|
||||
UCHAR OldTrampoline[INT16_TRAMPOLINE_SIZE];
|
||||
|
||||
DPRINT("Int32Call(0x%X)\n", IntNumber);
|
||||
|
||||
/* Save the old trampoline */
|
||||
((PULONGLONG)&OldTrampoline)[0] = ((PULONGLONG)TrampolineBase)[0];
|
||||
|
||||
/* Build the generic entry-point for 16-bit calls */
|
||||
if (IntNumber == 0x03)
|
||||
{
|
||||
/* We are redefining for INT 03h */
|
||||
*Trampoline++ = 0xCC; // Call INT 03h
|
||||
/** *Trampoline++ = 0x90; // nop **/
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal interrupt */
|
||||
*Trampoline++ = 0xCD; // Call INT XXh
|
||||
*Trampoline++ = IntNumber;
|
||||
}
|
||||
UnSimulate16(Trampoline);
|
||||
|
||||
/* Perform the call */
|
||||
Call16(HIWORD(Context->TrampolineFarPtr),
|
||||
LOWORD(Context->TrampolineFarPtr));
|
||||
|
||||
/* Restore the old trampoline */
|
||||
((PULONGLONG)TrampolineBase)[0] = ((PULONGLONG)&OldTrampoline)[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID WINAPI Int32Dispatch(LPWORD Stack)
|
||||
{
|
||||
/* Get the interrupt number */
|
||||
BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]);
|
||||
|
||||
/* Call the 32-bit Interrupt handler */
|
||||
if (Int32Proc[IntNum] != NULL)
|
||||
Int32Proc[IntNum](Stack);
|
||||
else
|
||||
DPRINT1("Unhandled 32-bit interrupt: 0x%02X, AX = 0x%04X\n", IntNum, getAX());
|
||||
}
|
||||
|
||||
static VOID WINAPI ControlBop(LPWORD Stack)
|
||||
{
|
||||
/* Get the Function Number and skip it */
|
||||
BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
|
||||
setIP(getIP() + 1);
|
||||
|
||||
if (FuncNum == BOP_CONTROL_INT32)
|
||||
Int32Dispatch(Stack);
|
||||
else
|
||||
// DPRINT1("Unassigned Control BOP Function: 0x%02X\n", FuncNum);
|
||||
DisplayMessage(L"Unassigned Control BOP Function: 0x%02X\n", FuncNum);
|
||||
}
|
||||
|
||||
VOID InitializeCallbacks(VOID)
|
||||
{
|
||||
/* Register the Control BOP */
|
||||
RegisterBop(BOP_CONTROL, ControlBop);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: callback.h
|
||||
* PURPOSE: 32-bit Interrupt Handlers
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _CALLBACK_H_
|
||||
#define _CALLBACK_H_
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* 32-bit Interrupt Identifiers */
|
||||
#define EMULATOR_MAX_INT32_NUM 0xFF + 1
|
||||
|
||||
#define INT_HANDLER_OFFSET 0x1000
|
||||
#define COMMON_STUB_OFFSET 0x2000
|
||||
|
||||
|
||||
typedef struct _CALLBACK16
|
||||
{
|
||||
ULONG TrampolineFarPtr; // Where the trampoline zone is placed
|
||||
USHORT Segment;
|
||||
USHORT NextOffset;
|
||||
} CALLBACK16, *PCALLBACK16;
|
||||
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
typedef VOID (WINAPI *EMULATOR_INT32_PROC)(LPWORD Stack);
|
||||
|
||||
VOID
|
||||
InitializeContext(IN PCALLBACK16 Context,
|
||||
IN USHORT Segment,
|
||||
IN USHORT Offset);
|
||||
|
||||
VOID
|
||||
Call16(IN USHORT Segment,
|
||||
IN USHORT Offset);
|
||||
|
||||
ULONG
|
||||
RegisterCallback16(IN ULONG FarPtr,
|
||||
IN LPBYTE CallbackCode,
|
||||
IN SIZE_T CallbackSize,
|
||||
OUT PSIZE_T CodeSize OPTIONAL);
|
||||
|
||||
VOID
|
||||
RunCallback16(IN PCALLBACK16 Context,
|
||||
IN ULONG FarPtr);
|
||||
|
||||
ULONG
|
||||
RegisterInt16(IN ULONG FarPtr,
|
||||
IN BYTE IntNumber,
|
||||
IN LPBYTE CallbackCode,
|
||||
IN SIZE_T CallbackSize,
|
||||
OUT PSIZE_T CodeSize OPTIONAL);
|
||||
|
||||
ULONG
|
||||
RegisterInt32(IN ULONG FarPtr,
|
||||
IN BYTE IntNumber,
|
||||
IN EMULATOR_INT32_PROC IntHandler,
|
||||
OUT PSIZE_T CodeSize OPTIONAL);
|
||||
|
||||
VOID
|
||||
Int32Call(IN PCALLBACK16 Context,
|
||||
IN BYTE IntNumber);
|
||||
|
||||
VOID WINAPI Int32Dispatch(LPWORD Stack);
|
||||
VOID InitializeCallbacks(VOID);
|
||||
|
||||
#endif // _CALLBACK_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: clock.c
|
||||
* PURPOSE: Clock for VDM
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
|
||||
// #include "clock.h"
|
||||
|
||||
#include "hardware/cmos.h"
|
||||
#include "hardware/ps2.h"
|
||||
#include "hardware/timer.h"
|
||||
#include "hardware/vga.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/*
|
||||
* Activate IPS_DISPLAY if you want to display the
|
||||
* number of instructions per second, as well as
|
||||
* the computed number of ticks for the PIT.
|
||||
*/
|
||||
// #define IPS_DISPLAY
|
||||
|
||||
/*
|
||||
* Activate WORKING_TIMER when the PIT timing problem is fixed.
|
||||
*/
|
||||
// #define WORKING_TIMER
|
||||
|
||||
|
||||
/* Processor speed */
|
||||
#define STEPS_PER_CYCLE 256
|
||||
#define KBD_INT_CYCLES 16
|
||||
|
||||
/* VARIABLES ******************************************************************/
|
||||
|
||||
LARGE_INTEGER StartPerfCount, Frequency;
|
||||
|
||||
LARGE_INTEGER LastTimerTick, LastRtcTick, Counter;
|
||||
LONGLONG TimerTicks;
|
||||
DWORD StartTickCount, CurrentTickCount;
|
||||
DWORD LastClockUpdate;
|
||||
DWORD LastVerticalRefresh;
|
||||
INT KeyboardIntCounter = 0;
|
||||
|
||||
#ifdef IPS_DISPLAY
|
||||
DWORD LastCyclePrintout;
|
||||
DWORD Cycles = 0;
|
||||
#endif
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID ClockUpdate(VOID)
|
||||
{
|
||||
extern BOOLEAN CpuSimulate;
|
||||
UINT i;
|
||||
|
||||
#ifdef WORKING_TIMER
|
||||
DWORD PitResolution = PitGetResolution();
|
||||
#endif
|
||||
DWORD RtcFrequency = RtcGetTicksPerSecond();
|
||||
|
||||
/* Get the current number of ticks */
|
||||
CurrentTickCount = GetTickCount();
|
||||
|
||||
#ifdef WORKING_TIMER
|
||||
if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
|
||||
{
|
||||
/* Calculate the approximate performance counter value instead */
|
||||
Counter.QuadPart = StartPerfCount.QuadPart
|
||||
+ (CurrentTickCount - StartTickCount)
|
||||
* (Frequency.QuadPart / 1000);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Get the current performance counter value */
|
||||
QueryPerformanceCounter(&Counter);
|
||||
}
|
||||
|
||||
/* Get the number of PIT ticks that have passed */
|
||||
TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
|
||||
* PIT_BASE_FREQUENCY) / Frequency.QuadPart;
|
||||
|
||||
/* Update the PIT */
|
||||
if (TimerTicks > 0)
|
||||
{
|
||||
PitClock(TimerTicks);
|
||||
LastTimerTick = Counter;
|
||||
}
|
||||
|
||||
/* Check for RTC update */
|
||||
if ((CurrentTickCount - LastClockUpdate) >= 1000)
|
||||
{
|
||||
RtcTimeUpdate();
|
||||
LastClockUpdate = CurrentTickCount;
|
||||
}
|
||||
|
||||
/* Check for RTC periodic tick */
|
||||
if ((Counter.QuadPart - LastRtcTick.QuadPart)
|
||||
>= (Frequency.QuadPart / (LONGLONG)RtcFrequency))
|
||||
{
|
||||
RtcPeriodicTick();
|
||||
LastRtcTick = Counter;
|
||||
}
|
||||
|
||||
/* Check for vertical retrace */
|
||||
if ((CurrentTickCount - LastVerticalRefresh) >= 15)
|
||||
{
|
||||
VgaRefreshDisplay();
|
||||
LastVerticalRefresh = CurrentTickCount;
|
||||
}
|
||||
|
||||
if (++KeyboardIntCounter == KBD_INT_CYCLES)
|
||||
{
|
||||
GenerateKeyboardInterrupts();
|
||||
KeyboardIntCounter = 0;
|
||||
}
|
||||
|
||||
/* Horizontal retrace occurs as fast as possible */
|
||||
VgaHorizontalRetrace();
|
||||
|
||||
/* Continue CPU emulation */
|
||||
for (i = 0; VdmRunning && CpuSimulate && (i < STEPS_PER_CYCLE); i++)
|
||||
{
|
||||
EmulatorStep();
|
||||
#ifdef IPS_DISPLAY
|
||||
Cycles++;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IPS_DISPLAY
|
||||
if ((CurrentTickCount - LastCyclePrintout) >= 1000)
|
||||
{
|
||||
DPRINT1("NTVDM: %lu Instructions Per Second; TimerTicks = %I64d\n", Cycles, TimerTicks);
|
||||
LastCyclePrintout = CurrentTickCount;
|
||||
Cycles = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOLEAN ClockInitialize(VOID)
|
||||
{
|
||||
/* Initialize the performance counter (needed for hardware timers) */
|
||||
if (!QueryPerformanceFrequency(&Frequency))
|
||||
{
|
||||
wprintf(L"FATAL: Performance counter not available\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Find the starting performance and tick count */
|
||||
StartTickCount = GetTickCount();
|
||||
QueryPerformanceCounter(&StartPerfCount);
|
||||
|
||||
/* Set the different last counts to the starting count */
|
||||
LastClockUpdate = LastVerticalRefresh =
|
||||
#ifdef IPS_DISPLAY
|
||||
LastCyclePrintout =
|
||||
#endif
|
||||
StartTickCount;
|
||||
|
||||
/* Set the last timer ticks to the current time */
|
||||
LastTimerTick = LastRtcTick = StartPerfCount;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: clock.h
|
||||
* PURPOSE: Clock for VDM
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _CLOCK_H_
|
||||
#define _CLOCK_H_
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID ClockUpdate(VOID);
|
||||
BOOLEAN ClockInitialize(VOID);
|
||||
|
||||
#endif // _CLOCK_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dem.c
|
||||
* PURPOSE: DOS 32-bit Emulation Support Library -
|
||||
* This library is used by the built-in NTVDM DOS32 and by
|
||||
* the NT 16-bit DOS in Windows (via BOPs). It also exposes
|
||||
* exported functions that can be used by VDDs.
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "dem.h"
|
||||
#include "bop.h"
|
||||
|
||||
#include "bios/bios.h"
|
||||
#include "hardware/vga.h"
|
||||
|
||||
/* Extra PSDK/NDK Headers */
|
||||
#include <ndk/obtypes.h>
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
/**/extern BYTE CurrentDrive;/**/
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define BOP_DOS 0x50 // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
|
||||
#define BOP_CMD 0x54 // DOS Command Interpreter BOP (for COMMAND.COM)
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID WINAPI DosSystemBop(LPWORD Stack)
|
||||
{
|
||||
/* Get the Function Number and skip it */
|
||||
BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
|
||||
setIP(getIP() + 1);
|
||||
|
||||
switch (FuncNum)
|
||||
{
|
||||
case 0x11: // Load the DOS kernel
|
||||
{
|
||||
BOOLEAN Success;
|
||||
HANDLE hDosKernel;
|
||||
ULONG ulDosKernelSize = 0;
|
||||
|
||||
DPRINT1("You are loading Windows NT DOS!\n");
|
||||
|
||||
/* Open the DOS kernel file */
|
||||
hDosKernel = FileOpen("ntdos.sys", &ulDosKernelSize);
|
||||
|
||||
/* If we failed, bail out */
|
||||
if (hDosKernel == NULL) goto Quit;
|
||||
|
||||
/*
|
||||
* Attempt to load the DOS kernel into memory.
|
||||
* The segment where to load the DOS kernel is defined
|
||||
* by the DOS BIOS and is found in DI:0000 .
|
||||
*/
|
||||
Success = FileLoadByHandle(hDosKernel,
|
||||
REAL_TO_PHYS(TO_LINEAR(getDI(), 0x0000)),
|
||||
ulDosKernelSize,
|
||||
&ulDosKernelSize);
|
||||
|
||||
DPRINT1("Windows NT DOS loading %s at 0x%04X:0x%04X, size 0x%x ; GetLastError() = %u\n",
|
||||
(Success ? "succeeded" : "failed"),
|
||||
getDI(), 0x0000,
|
||||
ulDosKernelSize,
|
||||
GetLastError());
|
||||
|
||||
/* Close the DOS kernel file */
|
||||
FileClose(hDosKernel);
|
||||
|
||||
Quit:
|
||||
if (!Success)
|
||||
{
|
||||
/* We failed everything, stop the VDM */
|
||||
EmulatorTerminate();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
|
||||
DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum);
|
||||
// setCF(1); // Disable, otherwise we enter an infinite loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
|
||||
{
|
||||
/* Get the Function Number and skip it */
|
||||
BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
|
||||
setIP(getIP() + 1);
|
||||
|
||||
switch (FuncNum)
|
||||
{
|
||||
case 0x08: // Launch external command
|
||||
{
|
||||
#define CMDLINE_LENGTH 1024
|
||||
|
||||
BOOL Result;
|
||||
DWORD dwExitCode;
|
||||
|
||||
LPSTR Command = (LPSTR)SEG_OFF_TO_PTR(getDS(), getSI());
|
||||
LPSTR CmdPtr = Command;
|
||||
CHAR CommandLine[CMDLINE_LENGTH] = "";
|
||||
STARTUPINFOA StartupInfo;
|
||||
PROCESS_INFORMATION ProcessInformation;
|
||||
|
||||
/* NULL-terminate the command by removing the return carriage character */
|
||||
while (*CmdPtr != '\r') CmdPtr++;
|
||||
*CmdPtr = '\0';
|
||||
|
||||
DPRINT1("CMD Run Command '%s'\n", Command);
|
||||
|
||||
/* Spawn a user-defined 32-bit command preprocessor */
|
||||
|
||||
/* Build the command line */
|
||||
// FIXME: Use COMSPEC env var!!
|
||||
strcpy(CommandLine, "cmd.exe /c ");
|
||||
strcat(CommandLine, Command);
|
||||
|
||||
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
||||
ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
|
||||
|
||||
StartupInfo.cb = sizeof(StartupInfo);
|
||||
|
||||
VgaRefreshDisplay();
|
||||
VgaDetachFromConsole(FALSE);
|
||||
|
||||
Result = CreateProcessA(NULL,
|
||||
CommandLine,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&StartupInfo,
|
||||
&ProcessInformation);
|
||||
if (Result)
|
||||
{
|
||||
DPRINT1("Command '%s' launched successfully\n", Command);
|
||||
|
||||
/* Wait for process termination */
|
||||
WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
|
||||
|
||||
/* Get the exit code */
|
||||
GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
|
||||
|
||||
/* Close handles */
|
||||
CloseHandle(ProcessInformation.hThread);
|
||||
CloseHandle(ProcessInformation.hProcess);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("Failed when launched command '%s'\n");
|
||||
dwExitCode = GetLastError();
|
||||
}
|
||||
|
||||
VgaAttachToConsole();
|
||||
VgaRefreshDisplay();
|
||||
VidBiosSyncCursorPosition();
|
||||
|
||||
setAL((UCHAR)dwExitCode);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
DPRINT1("Unknown DOS CMD Interpreter BOP Function: 0x%02X\n", FuncNum);
|
||||
// setCF(1); // Disable, otherwise we enter an infinite loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName)
|
||||
{
|
||||
/* Register the DOS BOPs */
|
||||
RegisterBop(BOP_DOS, DosSystemBop );
|
||||
RegisterBop(BOP_CMD, DosCmdInterpreterBop);
|
||||
|
||||
if (DosKernelFileName)
|
||||
{
|
||||
BOOLEAN Success;
|
||||
HANDLE hDosBios;
|
||||
ULONG ulDosBiosSize = 0;
|
||||
|
||||
/* Open the DOS BIOS file */
|
||||
hDosBios = FileOpen(DosKernelFileName, &ulDosBiosSize);
|
||||
|
||||
/* If we failed, bail out */
|
||||
if (hDosBios == NULL) return FALSE;
|
||||
|
||||
/* Attempt to load the DOS BIOS into memory */
|
||||
Success = FileLoadByHandle(hDosBios,
|
||||
REAL_TO_PHYS(TO_LINEAR(0x0070, 0x0000)),
|
||||
ulDosBiosSize,
|
||||
&ulDosBiosSize);
|
||||
|
||||
DPRINT1("DOS BIOS loading %s at 0x%04X:0x%04X, size 0x%x ; GetLastError() = %u\n",
|
||||
(Success ? "succeeded" : "failed"),
|
||||
0x0070, 0x0000,
|
||||
ulDosBiosSize,
|
||||
GetLastError());
|
||||
|
||||
/* Close the DOS BIOS file */
|
||||
FileClose(hDosBios);
|
||||
|
||||
if (Success)
|
||||
{
|
||||
/* Position execution pointers and return */
|
||||
setCS(0x0070);
|
||||
setIP(0x0000);
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOLEAN Result;
|
||||
|
||||
Result = DosBIOSInitialize();
|
||||
// Result &= DosKRNLInitialize();
|
||||
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC EXPORTED APIS *******************************************************/
|
||||
|
||||
// demLFNCleanup
|
||||
// demLFNGetCurrentDirectory
|
||||
|
||||
// demGetFileTimeByHandle_WOW
|
||||
// demWOWLFNAllocateSearchHandle
|
||||
// demWOWLFNCloseSearchHandle
|
||||
// demWOWLFNEntry
|
||||
// demWOWLFNGetSearchHandle
|
||||
// demWOWLFNInit
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demClientErrorEx(IN HANDLE FileHandle,
|
||||
IN CHAR Unknown,
|
||||
IN BOOL Flag)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demFileDelete(IN LPCSTR FileName)
|
||||
{
|
||||
if (DeleteFileA(FileName)) SetLastError(ERROR_SUCCESS);
|
||||
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demFileFindFirst(OUT PVOID lpFindFileData,
|
||||
IN LPCSTR FileName,
|
||||
IN WORD AttribMask)
|
||||
{
|
||||
BOOLEAN Success = TRUE;
|
||||
WIN32_FIND_DATAA FindData;
|
||||
PDOS_FIND_FILE_BLOCK FindFileBlock = (PDOS_FIND_FILE_BLOCK)lpFindFileData;
|
||||
|
||||
/* Fill the block */
|
||||
FindFileBlock->DriveLetter = CurrentDrive + 'A';
|
||||
FindFileBlock->AttribMask = AttribMask;
|
||||
FindFileBlock->SearchHandle = FindFirstFileA(FileName, &FindData);
|
||||
if (FindFileBlock->SearchHandle == INVALID_HANDLE_VALUE) return GetLastError();
|
||||
|
||||
do
|
||||
{
|
||||
/* Check the attributes */
|
||||
if (!((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN |
|
||||
FILE_ATTRIBUTE_SYSTEM |
|
||||
FILE_ATTRIBUTE_DIRECTORY))
|
||||
& ~AttribMask))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((Success = FindNextFileA(FindFileBlock->SearchHandle, &FindData)));
|
||||
|
||||
if (!Success) return GetLastError();
|
||||
|
||||
FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes);
|
||||
FileTimeToDosDateTime(&FindData.ftLastWriteTime,
|
||||
&FindFileBlock->FileDate,
|
||||
&FindFileBlock->FileTime);
|
||||
FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF
|
||||
: FindData.nFileSizeLow;
|
||||
strcpy(FindFileBlock->FileName, FindData.cAlternateFileName);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demFileFindNext(OUT PVOID lpFindFileData)
|
||||
{
|
||||
WIN32_FIND_DATAA FindData;
|
||||
PDOS_FIND_FILE_BLOCK FindFileBlock = (PDOS_FIND_FILE_BLOCK)lpFindFileData;
|
||||
|
||||
do
|
||||
{
|
||||
if (!FindNextFileA(FindFileBlock->SearchHandle, &FindData))
|
||||
return GetLastError();
|
||||
|
||||
/* Update the block */
|
||||
FindFileBlock->Attributes = LOBYTE(FindData.dwFileAttributes);
|
||||
FileTimeToDosDateTime(&FindData.ftLastWriteTime,
|
||||
&FindFileBlock->FileDate,
|
||||
&FindFileBlock->FileTime);
|
||||
FindFileBlock->FileSize = FindData.nFileSizeHigh ? 0xFFFFFFFF
|
||||
: FindData.nFileSizeLow;
|
||||
strcpy(FindFileBlock->FileName, FindData.cAlternateFileName);
|
||||
}
|
||||
while((FindData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN |
|
||||
FILE_ATTRIBUTE_SYSTEM |
|
||||
FILE_ATTRIBUTE_DIRECTORY))
|
||||
& ~FindFileBlock->AttribMask);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
demGetPhysicalDriveType(IN UCHAR DriveNumber)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return DOSDEVICE_DRIVE_UNKNOWN;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
demIsShortPathName(IN LPCSTR Path,
|
||||
IN BOOL Unknown)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demSetCurrentDirectoryGetDrive(IN LPCSTR CurrentDirectory,
|
||||
OUT PUCHAR DriveNumber)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dem.h
|
||||
* PURPOSE: DOS 32-bit Emulation Support Library -
|
||||
* This library is used by the built-in NTVDM DOS32 and by
|
||||
* the NT 16-bit DOS in Windows (via BOPs). It also exposes
|
||||
* exported functions that can be used by VDDs.
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _DEM_H_
|
||||
#define _DEM_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
#include "dos32krnl/dos.h"
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN DosInitialize(IN LPCSTR DosKernelFileNames);
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demClientErrorEx
|
||||
(
|
||||
IN HANDLE FileHandle,
|
||||
IN CHAR Unknown,
|
||||
IN BOOL Flag
|
||||
);
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demFileDelete
|
||||
(
|
||||
IN LPCSTR FileName
|
||||
);
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demFileFindFirst
|
||||
(
|
||||
OUT PVOID lpFindFileData,
|
||||
IN LPCSTR FileName,
|
||||
IN WORD AttribMask
|
||||
);
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demFileFindNext
|
||||
(
|
||||
OUT PVOID lpFindFileData
|
||||
);
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
demGetPhysicalDriveType
|
||||
(
|
||||
IN UCHAR DriveNumber
|
||||
);
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
demIsShortPathName
|
||||
(
|
||||
IN LPCSTR Path,
|
||||
IN BOOL Unknown
|
||||
);
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
demSetCurrentDirectoryGetDrive
|
||||
(
|
||||
IN LPCSTR CurrentDirectory,
|
||||
OUT PUCHAR DriveNumber
|
||||
);
|
||||
|
||||
#endif // _DEM_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dos.c
|
||||
* PURPOSE: VDM DOS Kernel
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
|
||||
#include "dos.h"
|
||||
|
||||
#include "bios/bios.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
// static BYTE CurrentDrive;
|
||||
// static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
#if 0
|
||||
static WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten)
|
||||
{
|
||||
WORD Result = ERROR_SUCCESS;
|
||||
DWORD BytesWritten32 = 0;
|
||||
HANDLE Handle = DosGetRealHandle(FileHandle);
|
||||
WORD i;
|
||||
|
||||
DPRINT("DosWriteFile: FileHandle 0x%04X, Count 0x%04X\n",
|
||||
FileHandle,
|
||||
Count);
|
||||
|
||||
/* Make sure the handle is valid */
|
||||
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
|
||||
|
||||
if (IsConsoleHandle(Handle))
|
||||
{
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
/* Call the BIOS to print the character */
|
||||
VidBiosPrintCharacter(((LPBYTE)Buffer)[i], DOS_CHAR_ATTRIBUTE, Bda->VideoPage);
|
||||
BytesWritten32++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write the file */
|
||||
if (!WriteFile(Handle, Buffer, Count, &BytesWritten32, NULL))
|
||||
{
|
||||
/* Store the error code */
|
||||
Result = (WORD)GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
/* The number of bytes written is always 16-bit */
|
||||
*BytesWritten = LOWORD(BytesWritten32);
|
||||
|
||||
/* Return the error code */
|
||||
return Result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
CHAR DosReadCharacter(VOID)
|
||||
{
|
||||
CHAR Character = '\0';
|
||||
WORD BytesRead;
|
||||
|
||||
if (IsConsoleHandle(DosGetRealHandle(DOS_INPUT_HANDLE)))
|
||||
{
|
||||
/* Call the BIOS */
|
||||
Character = LOBYTE(BiosGetCharacter());
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use the file reading function */
|
||||
DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
|
||||
}
|
||||
|
||||
return Character;
|
||||
}
|
||||
|
||||
BOOLEAN DosCheckInput(VOID)
|
||||
{
|
||||
HANDLE Handle = DosGetRealHandle(DOS_INPUT_HANDLE);
|
||||
|
||||
if (IsConsoleHandle(Handle))
|
||||
{
|
||||
/* Save AX */
|
||||
USHORT AX = getAX();
|
||||
|
||||
/* Call the BIOS */
|
||||
setAH(0x01); // or 0x11 for enhanced, but what to choose?
|
||||
Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
|
||||
|
||||
/* Restore AX */
|
||||
setAX(AX);
|
||||
|
||||
/* Return keyboard status */
|
||||
return (getZF() == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD FileSizeHigh;
|
||||
DWORD FileSize = GetFileSize(Handle, &FileSizeHigh);
|
||||
LONG LocationHigh = 0;
|
||||
DWORD Location = SetFilePointer(Handle, 0, &LocationHigh, FILE_CURRENT);
|
||||
|
||||
return ((Location != FileSize) || (LocationHigh != FileSizeHigh));
|
||||
}
|
||||
}
|
||||
|
||||
VOID DosPrintCharacter(CHAR Character)
|
||||
{
|
||||
WORD BytesWritten;
|
||||
|
||||
/* Use the file writing function */
|
||||
DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten);
|
||||
}
|
||||
|
||||
BOOLEAN DosBIOSInitialize(VOID)
|
||||
{
|
||||
PDOS_MCB Mcb = SEGMENT_TO_MCB(FIRST_MCB_SEGMENT);
|
||||
|
||||
LPWSTR SourcePtr, Environment;
|
||||
LPSTR AsciiString;
|
||||
DWORD AsciiSize;
|
||||
LPSTR DestPtr = (LPSTR)SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0);
|
||||
|
||||
#if 0
|
||||
UCHAR i;
|
||||
CHAR CurrentDirectory[MAX_PATH];
|
||||
CHAR DosDirectory[DOS_DIR_LENGTH];
|
||||
LPSTR Path;
|
||||
|
||||
FILE *Stream;
|
||||
WCHAR Buffer[256];
|
||||
#endif
|
||||
|
||||
/* Initialize the MCB */
|
||||
Mcb->BlockType = 'Z';
|
||||
Mcb->Size = USER_MEMORY_SIZE;
|
||||
Mcb->OwnerPsp = 0;
|
||||
|
||||
/* Initialize the link MCB to the UMB area */
|
||||
Mcb = SEGMENT_TO_MCB(FIRST_MCB_SEGMENT + USER_MEMORY_SIZE + 1);
|
||||
Mcb->BlockType = 'M';
|
||||
Mcb->Size = UMB_START_SEGMENT - FIRST_MCB_SEGMENT - USER_MEMORY_SIZE - 2;
|
||||
Mcb->OwnerPsp = SYSTEM_PSP;
|
||||
|
||||
/* Initialize the UMB area */
|
||||
Mcb = SEGMENT_TO_MCB(UMB_START_SEGMENT);
|
||||
Mcb->BlockType = 'Z';
|
||||
Mcb->Size = UMB_END_SEGMENT - UMB_START_SEGMENT;
|
||||
Mcb->OwnerPsp = 0;
|
||||
|
||||
/* Get the environment strings */
|
||||
SourcePtr = Environment = GetEnvironmentStringsW();
|
||||
if (Environment == NULL) return FALSE;
|
||||
|
||||
/* Fill the DOS system environment block */
|
||||
while (*SourcePtr)
|
||||
{
|
||||
/* Get the size of the ASCII string */
|
||||
AsciiSize = WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
SourcePtr,
|
||||
-1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Allocate memory for the ASCII string */
|
||||
AsciiString = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AsciiSize);
|
||||
if (AsciiString == NULL)
|
||||
{
|
||||
FreeEnvironmentStringsW(Environment);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Convert to ASCII */
|
||||
WideCharToMultiByte(CP_ACP,
|
||||
0,
|
||||
SourcePtr,
|
||||
-1,
|
||||
AsciiString,
|
||||
AsciiSize,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Copy the string into DOS memory */
|
||||
strcpy(DestPtr, AsciiString);
|
||||
|
||||
/* Move to the next string */
|
||||
SourcePtr += wcslen(SourcePtr) + 1;
|
||||
DestPtr += strlen(AsciiString);
|
||||
*(DestPtr++) = 0;
|
||||
|
||||
/* Free the memory */
|
||||
HeapFree(GetProcessHeap(), 0, AsciiString);
|
||||
}
|
||||
*DestPtr = 0;
|
||||
|
||||
/* Free the memory allocated for environment strings */
|
||||
FreeEnvironmentStringsW(Environment);
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
/* Clear the current directory buffer */
|
||||
ZeroMemory(CurrentDirectories, sizeof(CurrentDirectories));
|
||||
|
||||
/* Get the current directory */
|
||||
if (!GetCurrentDirectoryA(MAX_PATH, CurrentDirectory))
|
||||
{
|
||||
// TODO: Use some kind of default path?
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Convert that to a DOS path */
|
||||
if (!GetShortPathNameA(CurrentDirectory, DosDirectory, DOS_DIR_LENGTH))
|
||||
{
|
||||
// TODO: Use some kind of default path?
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Set the drive */
|
||||
CurrentDrive = DosDirectory[0] - 'A';
|
||||
|
||||
/* Get the directory part of the path */
|
||||
Path = strchr(DosDirectory, '\\');
|
||||
if (Path != NULL)
|
||||
{
|
||||
/* Skip the backslash */
|
||||
Path++;
|
||||
}
|
||||
|
||||
/* Set the directory */
|
||||
if (Path != NULL)
|
||||
{
|
||||
strncpy(CurrentDirectories[CurrentDrive], Path, DOS_DIR_LENGTH);
|
||||
}
|
||||
|
||||
/* Read CONFIG.SYS */
|
||||
Stream = _wfopen(DOS_CONFIG_PATH, L"r");
|
||||
if (Stream != NULL)
|
||||
{
|
||||
while (fgetws(Buffer, sizeof(Buffer)/sizeof(Buffer[0]), Stream))
|
||||
{
|
||||
// TODO: Parse the line
|
||||
}
|
||||
fclose(Stream);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Register the DOS 32-bit Interrupts */
|
||||
// RegisterDosInt32(0x20, DosInt20h);
|
||||
|
||||
/* Initialize the DOS kernel */
|
||||
return DosKRNLInitialize();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: dos.h
|
||||
* PURPOSE: VDM DOS Kernel
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _DOS_H_
|
||||
#define _DOS_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/**/ #include "callback.h" /**/
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
//
|
||||
// We are DOS 5.00 (reported by INT 21h, AH=30h)
|
||||
// and DOS 5.50 (reported by INT 21h, AX=3306h) for Windows NT Compatibility
|
||||
//
|
||||
#define DOS_VERSION MAKEWORD(5, 00)
|
||||
#define NTDOS_VERSION MAKEWORD(5, 50)
|
||||
|
||||
#define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT"
|
||||
#define DOS_COMMAND_INTERPRETER L"%SystemRoot%\\system32\\COMMAND.COM /k %SystemRoot%\\system32\\AUTOEXEC.NT"
|
||||
#define FIRST_MCB_SEGMENT 0x1000
|
||||
#define USER_MEMORY_SIZE 0x8FFE
|
||||
#define SYSTEM_PSP 0x08
|
||||
#define SYSTEM_ENV_BLOCK 0x800
|
||||
#define INVALID_DOS_HANDLE 0xFFFF
|
||||
#define DOS_INPUT_HANDLE 0
|
||||
#define DOS_OUTPUT_HANDLE 1
|
||||
#define DOS_ERROR_HANDLE 2
|
||||
#define DOS_SFT_SIZE 255
|
||||
#define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
|
||||
#define SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
|
||||
#define UMB_START_SEGMENT 0xC000
|
||||
#define UMB_END_SEGMENT 0xDFFF
|
||||
#define DOS_ALLOC_HIGH 0x40
|
||||
#define DOS_ALLOC_HIGH_LOW 0x80
|
||||
#define DOS_CMDLINE_LENGTH 127
|
||||
#define DOS_DIR_LENGTH 64
|
||||
#define NUM_DRIVES ('Z' - 'A' + 1)
|
||||
#define DOS_CHAR_ATTRIBUTE 0x07
|
||||
|
||||
enum DOS_ALLOC_STRATEGY
|
||||
{
|
||||
DOS_ALLOC_FIRST_FIT,
|
||||
DOS_ALLOC_BEST_FIT,
|
||||
DOS_ALLOC_LAST_FIT
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DOS_LOAD_AND_EXECUTE = 0x00,
|
||||
DOS_LOAD_ONLY = 0x01,
|
||||
DOS_LOAD_OVERLAY = 0x03
|
||||
} DOS_EXEC_TYPE;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct _DOS_MCB
|
||||
{
|
||||
CHAR BlockType;
|
||||
WORD OwnerPsp;
|
||||
WORD Size;
|
||||
BYTE Unused[3];
|
||||
CHAR Name[8];
|
||||
} DOS_MCB, *PDOS_MCB;
|
||||
|
||||
typedef struct _DOS_FCB
|
||||
{
|
||||
BYTE DriveNumber;
|
||||
CHAR FileName[8];
|
||||
CHAR FileExt[3];
|
||||
WORD BlockNumber;
|
||||
WORD RecordSize;
|
||||
DWORD FileSize;
|
||||
WORD LastWriteDate;
|
||||
WORD LastWriteTime;
|
||||
BYTE Reserved[8];
|
||||
BYTE BlockRecord;
|
||||
BYTE RecordNumber[3];
|
||||
} DOS_FCB, *PDOS_FCB;
|
||||
|
||||
typedef struct _DOS_PSP
|
||||
{
|
||||
BYTE Exit[2];
|
||||
WORD LastParagraph;
|
||||
BYTE Reserved0[6];
|
||||
DWORD TerminateAddress;
|
||||
DWORD BreakAddress;
|
||||
DWORD CriticalAddress;
|
||||
WORD ParentPsp;
|
||||
BYTE HandleTable[20];
|
||||
WORD EnvBlock;
|
||||
DWORD LastStack;
|
||||
WORD HandleTableSize;
|
||||
DWORD HandleTablePtr;
|
||||
DWORD PreviousPsp;
|
||||
DWORD Reserved1;
|
||||
WORD DosVersion;
|
||||
BYTE Reserved2[14];
|
||||
BYTE FarCall[3];
|
||||
BYTE Reserved3[9];
|
||||
DOS_FCB Fcb;
|
||||
BYTE CommandLineSize;
|
||||
CHAR CommandLine[DOS_CMDLINE_LENGTH];
|
||||
} DOS_PSP, *PDOS_PSP;
|
||||
|
||||
typedef struct _DOS_INPUT_BUFFER
|
||||
{
|
||||
BYTE MaxLength;
|
||||
BYTE Length;
|
||||
CHAR Buffer[ANYSIZE_ARRAY];
|
||||
} DOS_INPUT_BUFFER, *PDOS_INPUT_BUFFER;
|
||||
|
||||
typedef struct _DOS_DRIVER_HEADER
|
||||
{
|
||||
DWORD NextDriver;
|
||||
WORD Attributes;
|
||||
WORD StrategyEntry;
|
||||
WORD InterruptEntry;
|
||||
CHAR DeviceName[8];
|
||||
} DOS_DRIVER_HEADER, *PDOS_DRIVER_HEADER;
|
||||
|
||||
typedef struct _DOS_FIND_FILE_BLOCK
|
||||
{
|
||||
CHAR DriveLetter;
|
||||
CHAR Pattern[11];
|
||||
UCHAR AttribMask;
|
||||
DWORD Unused;
|
||||
HANDLE SearchHandle;
|
||||
|
||||
/* The following part of the structure is documented */
|
||||
UCHAR Attributes;
|
||||
WORD FileTime;
|
||||
WORD FileDate;
|
||||
DWORD FileSize;
|
||||
CHAR FileName[13];
|
||||
} DOS_FIND_FILE_BLOCK, *PDOS_FIND_FILE_BLOCK;
|
||||
|
||||
typedef struct _DOS_EXEC_PARAM_BLOCK
|
||||
{
|
||||
/* Input variables */
|
||||
WORD Environment;
|
||||
DWORD CommandLine;
|
||||
DWORD FirstFcb;
|
||||
DWORD SecondFcb;
|
||||
|
||||
/* Output variables */
|
||||
DWORD StackLocation;
|
||||
DWORD EntryPoint;
|
||||
} DOS_EXEC_PARAM_BLOCK, *PDOS_EXEC_PARAM_BLOCK;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
extern CALLBACK16 DosContext;
|
||||
#define RegisterDosInt32(IntNumber, IntHandler) \
|
||||
do { \
|
||||
DosContext.NextOffset += RegisterInt32(MAKELONG(DosContext.NextOffset, \
|
||||
DosContext.Segment), \
|
||||
(IntNumber), (IntHandler), NULL); \
|
||||
} while(0);
|
||||
|
||||
/*
|
||||
* DOS BIOS Functions
|
||||
* See bios.c
|
||||
*/
|
||||
CHAR DosReadCharacter(VOID);
|
||||
BOOLEAN DosCheckInput(VOID);
|
||||
VOID DosPrintCharacter(CHAR Character);
|
||||
|
||||
BOOLEAN DosBIOSInitialize(VOID);
|
||||
|
||||
|
||||
/*
|
||||
* DOS Kernel Functions
|
||||
* See dos.c
|
||||
*/
|
||||
BOOL IsConsoleHandle(HANDLE hHandle);
|
||||
HANDLE DosGetRealHandle(WORD DosHandle);
|
||||
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead);
|
||||
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
|
||||
|
||||
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment);
|
||||
DWORD DosLoadExecutable(
|
||||
IN DOS_EXEC_TYPE LoadType,
|
||||
IN LPCSTR ExecutablePath,
|
||||
IN LPCSTR CommandLine,
|
||||
IN PVOID Environment,
|
||||
OUT PDWORD StackLocation OPTIONAL,
|
||||
OUT PDWORD EntryPoint OPTIONAL
|
||||
);
|
||||
WORD DosCreateProcess(
|
||||
DOS_EXEC_TYPE LoadType,
|
||||
LPCSTR ProgramName,
|
||||
PDOS_EXEC_PARAM_BLOCK Parameters
|
||||
);
|
||||
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
|
||||
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);
|
||||
|
||||
VOID WINAPI DosInt20h(LPWORD Stack);
|
||||
VOID WINAPI DosInt21h(LPWORD Stack);
|
||||
VOID WINAPI DosBreakInterrupt(LPWORD Stack);
|
||||
VOID WINAPI DosInt2Fh(LPWORD Stack);
|
||||
|
||||
BOOLEAN DosKRNLInitialize(VOID);
|
||||
|
||||
#endif // _DOS_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: emulator.c
|
||||
* PURPOSE: Minimal x86 machine emulator for the VDM
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "callback.h"
|
||||
|
||||
#include "clock.h"
|
||||
#include "bios/rom.h"
|
||||
#include "hardware/cmos.h"
|
||||
#include "hardware/pic.h"
|
||||
#include "hardware/ps2.h"
|
||||
#include "hardware/speaker.h"
|
||||
#include "hardware/timer.h"
|
||||
#include "hardware/vga.h"
|
||||
|
||||
#include "bop.h"
|
||||
#include "vddsup.h"
|
||||
#include "io.h"
|
||||
|
||||
#include <isvbop.h>
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
FAST486_STATE EmulatorContext;
|
||||
BOOLEAN CpuSimulate = FALSE;
|
||||
|
||||
/* No more than 'MaxCpuCallLevel' recursive CPU calls are allowed */
|
||||
const static INT MaxCpuCallLevel = 32;
|
||||
static INT CpuCallLevel = 0;
|
||||
|
||||
LPVOID BaseAddress = NULL;
|
||||
BOOLEAN VdmRunning = TRUE;
|
||||
|
||||
static BOOLEAN A20Line = FALSE;
|
||||
static BYTE Port61hState = 0x00;
|
||||
|
||||
static HANDLE InputThread = NULL;
|
||||
|
||||
LPCWSTR ExceptionName[] =
|
||||
{
|
||||
L"Division By Zero",
|
||||
L"Debug",
|
||||
L"Unexpected Error",
|
||||
L"Breakpoint",
|
||||
L"Integer Overflow",
|
||||
L"Bound Range Exceeded",
|
||||
L"Invalid Opcode",
|
||||
L"FPU Not Available"
|
||||
};
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
VOID WINAPI EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
||||
{
|
||||
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 (!A20Line) Address &= ~(1 << 20);
|
||||
|
||||
/* Make sure the requested address is valid */
|
||||
if ((Address + Size) >= MAX_ADDRESS) return;
|
||||
|
||||
/*
|
||||
* Check if we are going to read the VGA memory and
|
||||
* 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 */
|
||||
RtlCopyMemory(Buffer, REAL_TO_PHYS(Address), Size);
|
||||
}
|
||||
|
||||
VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
|
||||
{
|
||||
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 (!A20Line) Address &= ~(1 << 20);
|
||||
|
||||
/* Make sure the requested address is valid */
|
||||
if ((Address + Size) >= MAX_ADDRESS) return;
|
||||
|
||||
/* Make sure we don't write to the ROM area */
|
||||
if ((Address + Size) >= ROM_AREA_START && (Address < ROM_AREA_END)) return;
|
||||
|
||||
/* Read the data from the buffer and store it in the virtual address space */
|
||||
RtlCopyMemory(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)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
|
||||
/* Get the interrupt number from the PIC */
|
||||
return PicGetInterrupt();
|
||||
}
|
||||
|
||||
VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
|
||||
{
|
||||
WORD CodeSegment, InstructionPointer;
|
||||
PBYTE Opcode;
|
||||
|
||||
ASSERT(ExceptionNumber < 8);
|
||||
|
||||
/* Get the CS:IP */
|
||||
InstructionPointer = Stack[STACK_IP];
|
||||
CodeSegment = Stack[STACK_CS];
|
||||
Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
|
||||
|
||||
/* Display a message to the user */
|
||||
DisplayMessage(L"Exception: %s occured at %04X:%04X\n"
|
||||
L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
|
||||
ExceptionName[ExceptionNumber],
|
||||
CodeSegment,
|
||||
InstructionPointer,
|
||||
Opcode[0],
|
||||
Opcode[1],
|
||||
Opcode[2],
|
||||
Opcode[3],
|
||||
Opcode[4],
|
||||
Opcode[5],
|
||||
Opcode[6],
|
||||
Opcode[7],
|
||||
Opcode[8],
|
||||
Opcode[9]);
|
||||
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: This function assumes 16-bit mode!!!
|
||||
VOID EmulatorExecute(WORD Segment, WORD Offset)
|
||||
{
|
||||
/* Tell Fast486 to move the instruction pointer */
|
||||
Fast486ExecuteAt(&EmulatorContext, Segment, Offset);
|
||||
}
|
||||
|
||||
VOID EmulatorStep(VOID)
|
||||
{
|
||||
/* Dump the state for debugging purposes */
|
||||
// Fast486DumpState(&EmulatorContext);
|
||||
|
||||
/* Execute the next instruction */
|
||||
Fast486StepInto(&EmulatorContext);
|
||||
}
|
||||
|
||||
VOID EmulatorSimulate(VOID)
|
||||
{
|
||||
if (CpuCallLevel > MaxCpuCallLevel)
|
||||
{
|
||||
DisplayMessage(L"Too many CPU levels of recursion (%d, expected maximum %d)",
|
||||
CpuCallLevel, MaxCpuCallLevel);
|
||||
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
return;
|
||||
}
|
||||
CpuCallLevel++;
|
||||
|
||||
CpuSimulate = TRUE;
|
||||
while (VdmRunning && CpuSimulate) ClockUpdate();
|
||||
|
||||
CpuCallLevel--;
|
||||
if (CpuCallLevel < 0) CpuCallLevel = 0;
|
||||
|
||||
/* This takes into account for reentrance */
|
||||
CpuSimulate = TRUE;
|
||||
}
|
||||
|
||||
VOID EmulatorUnsimulate(VOID)
|
||||
{
|
||||
/* Stop simulation */
|
||||
CpuSimulate = FALSE;
|
||||
}
|
||||
|
||||
VOID EmulatorTerminate(VOID)
|
||||
{
|
||||
/* Stop the VDM */
|
||||
VdmRunning = FALSE;
|
||||
}
|
||||
|
||||
VOID EmulatorInterrupt(BYTE Number)
|
||||
{
|
||||
/* Call the Fast486 API */
|
||||
Fast486Interrupt(&EmulatorContext, Number);
|
||||
}
|
||||
|
||||
VOID EmulatorInterruptSignal(VOID)
|
||||
{
|
||||
/* Call the Fast486 API */
|
||||
Fast486InterruptSignal(&EmulatorContext);
|
||||
}
|
||||
|
||||
VOID EmulatorSetA20(BOOLEAN Enabled)
|
||||
{
|
||||
A20Line = Enabled;
|
||||
}
|
||||
|
||||
static VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack)
|
||||
{
|
||||
DPRINT1("NTVDM: BOP_DEBUGGER\n");
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
static VOID WINAPI EmulatorUnsimulateBop(LPWORD Stack)
|
||||
{
|
||||
EmulatorUnsimulate();
|
||||
}
|
||||
|
||||
static BYTE WINAPI Port61hRead(ULONG Port)
|
||||
{
|
||||
return Port61hState;
|
||||
}
|
||||
|
||||
static VOID WINAPI Port61hWrite(ULONG Port, BYTE Data)
|
||||
{
|
||||
// BOOLEAN SpeakerChange = FALSE;
|
||||
BYTE OldPort61hState = Port61hState;
|
||||
|
||||
/* Only the four lowest bytes can be written */
|
||||
Port61hState = (Port61hState & 0xF0) | (Data & 0x0F);
|
||||
|
||||
if ((OldPort61hState ^ Port61hState) & 0x01)
|
||||
{
|
||||
DPRINT("PIT 2 Gate %s\n", Port61hState & 0x01 ? "on" : "off");
|
||||
// SpeakerChange = TRUE;
|
||||
}
|
||||
|
||||
PitSetGate(2, !!(Port61hState & 0x01));
|
||||
|
||||
if ((OldPort61hState ^ Port61hState) & 0x02)
|
||||
{
|
||||
/* There were some change for the speaker... */
|
||||
DPRINT("Speaker %s\n", Port61hState & 0x02 ? "on" : "off");
|
||||
// SpeakerChange = TRUE;
|
||||
}
|
||||
// if (SpeakerChange) SpeakerChange();
|
||||
SpeakerChange();
|
||||
}
|
||||
|
||||
static VOID WINAPI PitChan0Out(LPVOID Param, BOOLEAN State)
|
||||
{
|
||||
if (State)
|
||||
{
|
||||
DPRINT("PicInterruptRequest\n");
|
||||
PicInterruptRequest(0); // Raise IRQ 0
|
||||
}
|
||||
// else < Lower IRQ 0 >
|
||||
}
|
||||
|
||||
static VOID WINAPI PitChan1Out(LPVOID Param, BOOLEAN State)
|
||||
{
|
||||
#if 0
|
||||
if (State)
|
||||
{
|
||||
/* Set bit 4 of Port 61h */
|
||||
Port61hState |= 1 << 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear bit 4 of Port 61h */
|
||||
Port61hState &= ~(1 << 4);
|
||||
}
|
||||
#else
|
||||
Port61hState = (Port61hState & 0xEF) | (State << 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
|
||||
{
|
||||
// BYTE OldPort61hState = Port61hState;
|
||||
|
||||
#if 0
|
||||
if (State)
|
||||
{
|
||||
/* Set bit 5 of Port 61h */
|
||||
Port61hState |= 1 << 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear bit 5 of Port 61h */
|
||||
Port61hState &= ~(1 << 5);
|
||||
}
|
||||
#else
|
||||
Port61hState = (Port61hState & 0xDF) | (State << 5);
|
||||
#endif
|
||||
DPRINT("Speaker PIT out\n");
|
||||
// if ((OldPort61hState ^ Port61hState) & 0x20)
|
||||
// SpeakerChange();
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
DWORD WINAPI PumpConsoleInput(LPVOID Parameter);
|
||||
|
||||
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
||||
{
|
||||
/* Allocate memory for the 16-bit address space */
|
||||
BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS);
|
||||
if (BaseAddress == NULL)
|
||||
{
|
||||
wprintf(L"FATAL: Failed to allocate VDM memory.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Initialize I/O ports */
|
||||
/* Initialize RAM */
|
||||
|
||||
/* Initialize the internal clock */
|
||||
if (!ClockInitialize())
|
||||
{
|
||||
wprintf(L"FATAL: Failed to initialize the clock\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Initialize the CPU */
|
||||
Fast486Initialize(&EmulatorContext,
|
||||
EmulatorReadMemory,
|
||||
EmulatorWriteMemory,
|
||||
EmulatorReadIo,
|
||||
EmulatorWriteIo,
|
||||
NULL,
|
||||
EmulatorBiosOperation,
|
||||
EmulatorIntAcknowledge,
|
||||
NULL /* TODO: Use a TLB */);
|
||||
|
||||
/* Initialize DMA */
|
||||
|
||||
/* Initialize the PIC, the PIT, the CMOS and the PC Speaker */
|
||||
PicInitialize();
|
||||
PitInitialize();
|
||||
CmosInitialize();
|
||||
SpeakerInitialize();
|
||||
|
||||
/* Set output functions */
|
||||
PitSetOutFunction(0, NULL, PitChan0Out);
|
||||
PitSetOutFunction(1, NULL, PitChan1Out);
|
||||
PitSetOutFunction(2, NULL, PitChan2Out);
|
||||
|
||||
/* Register the I/O Ports */
|
||||
RegisterIoPort(CONTROL_SYSTEM_PORT61H, Port61hRead, Port61hWrite);
|
||||
|
||||
/* Set the console input mode */
|
||||
// FIXME: Activate ENABLE_WINDOW_INPUT when we will want to perform actions
|
||||
// upon console window events (screen buffer resize, ...).
|
||||
SetConsoleMode(ConsoleInput, ENABLE_PROCESSED_INPUT /* | ENABLE_WINDOW_INPUT */);
|
||||
// SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
|
||||
/* Initialize the PS2 port */
|
||||
PS2Initialize(ConsoleInput);
|
||||
|
||||
/* Start the input thread */
|
||||
InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL);
|
||||
// if (InputThread == NULL) return FALSE;
|
||||
|
||||
/* Initialize the VGA */
|
||||
// if (!VgaInitialize(ConsoleOutput)) return FALSE;
|
||||
VgaInitialize(ConsoleOutput);
|
||||
|
||||
/* Initialize the software callback system and register the emulator BOPs */
|
||||
InitializeCallbacks();
|
||||
RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
|
||||
RegisterBop(BOP_UNSIMULATE, EmulatorUnsimulateBop);
|
||||
|
||||
/* Initialize VDD support */
|
||||
VDDSupInitialize();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID EmulatorCleanup(VOID)
|
||||
{
|
||||
VgaCleanup();
|
||||
|
||||
/* Close the input thread handle */
|
||||
if (InputThread != NULL) CloseHandle(InputThread);
|
||||
InputThread = NULL;
|
||||
|
||||
PS2Cleanup();
|
||||
|
||||
SpeakerCleanup();
|
||||
CmosCleanup();
|
||||
// PitCleanup();
|
||||
// PicCleanup();
|
||||
|
||||
// Fast486Cleanup();
|
||||
|
||||
/* Free the memory allocated for the 16-bit address space */
|
||||
if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDSimulate16(VOID)
|
||||
{
|
||||
EmulatorSimulate();
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDTerminateVDM(VOID)
|
||||
{
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
}
|
||||
|
||||
PBYTE
|
||||
WINAPI
|
||||
Sim32pGetVDMPointer(IN ULONG Address,
|
||||
IN BOOLEAN ProtectedMode)
|
||||
{
|
||||
// FIXME
|
||||
UNREFERENCED_PARAMETER(ProtectedMode);
|
||||
|
||||
/*
|
||||
* HIWORD(Address) == Segment (if ProtectedMode == FALSE)
|
||||
* or Selector (if ProtectedMode == TRUE )
|
||||
* LOWORD(Address) == Offset
|
||||
*/
|
||||
return (PBYTE)FAR_POINTER(Address);
|
||||
}
|
||||
|
||||
PBYTE
|
||||
WINAPI
|
||||
MGetVdmPointer(IN ULONG Address,
|
||||
IN ULONG Size,
|
||||
IN BOOLEAN ProtectedMode)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Size);
|
||||
return Sim32pGetVDMPointer(Address, ProtectedMode);
|
||||
}
|
||||
|
||||
PVOID
|
||||
WINAPI
|
||||
VdmMapFlat(IN USHORT Segment,
|
||||
IN ULONG Offset,
|
||||
IN VDM_MODE Mode)
|
||||
{
|
||||
// FIXME
|
||||
UNREFERENCED_PARAMETER(Mode);
|
||||
|
||||
return SEG_OFF_TO_PTR(Segment, Offset);
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
VdmFlushCache(IN USHORT Segment,
|
||||
IN ULONG Offset,
|
||||
IN ULONG Size,
|
||||
IN VDM_MODE Mode)
|
||||
{
|
||||
// FIXME
|
||||
UNIMPLEMENTED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
VdmUnmapFlat(IN USHORT Segment,
|
||||
IN ULONG Offset,
|
||||
IN PVOID Buffer,
|
||||
IN VDM_MODE Mode)
|
||||
{
|
||||
// FIXME
|
||||
UNIMPLEMENTED;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: emulator.h
|
||||
* PURPOSE: Minimal x86 machine emulator for the VDM
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _EMULATOR_H_
|
||||
#define _EMULATOR_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
#include <fast486.h>
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* FLAGS */
|
||||
#define EMULATOR_FLAG_CF (1 << 0)
|
||||
#define EMULATOR_FLAG_PF (1 << 2)
|
||||
#define EMULATOR_FLAG_AF (1 << 4)
|
||||
#define EMULATOR_FLAG_ZF (1 << 6)
|
||||
#define EMULATOR_FLAG_SF (1 << 7)
|
||||
#define EMULATOR_FLAG_TF (1 << 8)
|
||||
#define EMULATOR_FLAG_IF (1 << 9)
|
||||
#define EMULATOR_FLAG_DF (1 << 10)
|
||||
#define EMULATOR_FLAG_OF (1 << 11)
|
||||
#define EMULATOR_FLAG_NT (1 << 14)
|
||||
#define EMULATOR_FLAG_RF (1 << 16)
|
||||
#define EMULATOR_FLAG_VM (1 << 17)
|
||||
#define EMULATOR_FLAG_AC (1 << 18)
|
||||
#define EMULATOR_FLAG_VIF (1 << 19)
|
||||
#define EMULATOR_FLAG_VIP (1 << 20)
|
||||
#define EMULATOR_FLAG_ID (1 << 21)
|
||||
|
||||
#define STACK_VAR_B 0
|
||||
#define STACK_VAR_A 1
|
||||
#define STACK_COUNTER 2
|
||||
#define STACK_INT_NUM 3
|
||||
#define STACK_IP 4
|
||||
#define STACK_CS 5
|
||||
#define STACK_FLAGS 6
|
||||
|
||||
|
||||
/* Basic Memory Management */
|
||||
#define MEM_ALIGN_UP(ptr, align) MEM_ALIGN_DOWN((ULONG_PTR)(ptr) + (align) - 1l, (align))
|
||||
#define MEM_ALIGN_DOWN(ptr, align) (PVOID)((ULONG_PTR)(ptr) & ~((align) - 1l))
|
||||
|
||||
#define TO_LINEAR(seg, off) (((seg) << 4) + (off))
|
||||
#define MAX_SEGMENT 0xFFFF
|
||||
#define MAX_OFFSET 0xFFFF
|
||||
#define MAX_ADDRESS 0x1000000 // 16 MB of RAM
|
||||
|
||||
#define FAR_POINTER(x) \
|
||||
(PVOID)((ULONG_PTR)BaseAddress + TO_LINEAR(HIWORD(x), LOWORD(x)))
|
||||
|
||||
#define SEG_OFF_TO_PTR(seg, off) \
|
||||
(PVOID)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), (off)))
|
||||
|
||||
#define REAL_TO_PHYS(ptr) (PVOID)((ULONG_PTR)(ptr) + (ULONG_PTR)BaseAddress)
|
||||
#define PHYS_TO_REAL(ptr) (PVOID)((ULONG_PTR)(ptr) - (ULONG_PTR)BaseAddress)
|
||||
|
||||
|
||||
/* BCD-Binary conversion */
|
||||
#define BINARY_TO_BCD(x) ((((x) / 1000) << 12) + (((x) / 100) << 8) + (((x) / 10) << 4) + ((x) % 10))
|
||||
#define BCD_TO_BINARY(x) (((x) >> 12) * 1000 + ((x) >> 8) * 100 + ((x) >> 4) * 10 + ((x) & 0x0F))
|
||||
|
||||
|
||||
/* System I/O ports */
|
||||
#define CONTROL_SYSTEM_PORT61H 0x61
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
EMULATOR_EXCEPTION_DIVISION_BY_ZERO,
|
||||
EMULATOR_EXCEPTION_DEBUG,
|
||||
EMULATOR_EXCEPTION_NMI,
|
||||
EMULATOR_EXCEPTION_BREAKPOINT,
|
||||
EMULATOR_EXCEPTION_OVERFLOW,
|
||||
EMULATOR_EXCEPTION_BOUND,
|
||||
EMULATOR_EXCEPTION_INVALID_OPCODE,
|
||||
EMULATOR_EXCEPTION_NO_FPU,
|
||||
EMULATOR_EXCEPTION_DOUBLE_FAULT,
|
||||
EMULATOR_EXCEPTION_FPU_SEGMENT,
|
||||
EMULATOR_EXCEPTION_INVALID_TSS,
|
||||
EMULATOR_EXCEPTION_NO_SEGMENT,
|
||||
EMULATOR_EXCEPTION_STACK_SEGMENT,
|
||||
EMULATOR_EXCEPTION_GPF,
|
||||
EMULATOR_EXCEPTION_PAGE_FAULT
|
||||
};
|
||||
|
||||
extern FAST486_STATE EmulatorContext;
|
||||
extern LPVOID BaseAddress;
|
||||
extern BOOLEAN VdmRunning;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID WINAPI EmulatorReadMemory
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Address,
|
||||
PVOID Buffer,
|
||||
ULONG Size
|
||||
);
|
||||
|
||||
VOID WINAPI EmulatorWriteMemory
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Address,
|
||||
PVOID Buffer,
|
||||
ULONG Size
|
||||
);
|
||||
|
||||
UCHAR WINAPI EmulatorIntAcknowledge
|
||||
(
|
||||
PFAST486_STATE State
|
||||
);
|
||||
|
||||
VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack);
|
||||
|
||||
VOID EmulatorExecute(WORD Segment, WORD Offset);
|
||||
VOID EmulatorStep(VOID);
|
||||
VOID EmulatorSimulate(VOID);
|
||||
VOID EmulatorUnsimulate(VOID);
|
||||
VOID EmulatorTerminate(VOID);
|
||||
|
||||
VOID EmulatorInterrupt(BYTE Number);
|
||||
VOID EmulatorInterruptSignal(VOID);
|
||||
VOID EmulatorSetA20(BOOLEAN Enabled);
|
||||
|
||||
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput);
|
||||
VOID EmulatorCleanup(VOID);
|
||||
|
||||
#endif // _EMULATOR_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: cmos.c
|
||||
* PURPOSE: CMOS Real Time Clock emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "cmos.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static HANDLE hCmosRam = INVALID_HANDLE_VALUE;
|
||||
static CMOS_MEMORY CmosMemory;
|
||||
|
||||
static BOOLEAN NmiEnabled = TRUE;
|
||||
static CMOS_REGISTERS SelectedRegister = CMOS_REG_STATUS_D;
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN IsNmiEnabled(VOID)
|
||||
{
|
||||
return NmiEnabled;
|
||||
}
|
||||
|
||||
VOID CmosWriteAddress(BYTE Value)
|
||||
{
|
||||
/* Update the NMI enabled flag */
|
||||
NmiEnabled = !(Value & CMOS_DISABLE_NMI);
|
||||
|
||||
/* Get the register number */
|
||||
Value &= ~CMOS_DISABLE_NMI;
|
||||
|
||||
if (Value < CMOS_REG_MAX)
|
||||
{
|
||||
/* Select the new register */
|
||||
SelectedRegister = Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Default to Status Register D */
|
||||
SelectedRegister = CMOS_REG_STATUS_D;
|
||||
}
|
||||
}
|
||||
|
||||
BYTE CmosReadData(VOID)
|
||||
{
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
||||
/* Get the current time */
|
||||
GetLocalTime(&CurrentTime);
|
||||
|
||||
switch (SelectedRegister)
|
||||
{
|
||||
case CMOS_REG_SECONDS:
|
||||
return READ_CMOS_DATA(CmosMemory, CurrentTime.wSecond);
|
||||
|
||||
case CMOS_REG_ALARM_SEC:
|
||||
return READ_CMOS_DATA(CmosMemory, CmosMemory.AlarmSecond);
|
||||
|
||||
case CMOS_REG_MINUTES:
|
||||
return READ_CMOS_DATA(CmosMemory, CurrentTime.wMinute);
|
||||
|
||||
case CMOS_REG_ALARM_MIN:
|
||||
return READ_CMOS_DATA(CmosMemory, CmosMemory.AlarmMinute);
|
||||
|
||||
case CMOS_REG_HOURS:
|
||||
{
|
||||
BOOLEAN Afternoon = FALSE;
|
||||
BYTE Value = CurrentTime.wHour;
|
||||
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
|
||||
{
|
||||
Value -= 12;
|
||||
Afternoon = TRUE;
|
||||
}
|
||||
|
||||
Value = READ_CMOS_DATA(CmosMemory, Value);
|
||||
|
||||
/* Convert to 12-hour */
|
||||
if (Afternoon) Value |= 0x80;
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
case CMOS_REG_ALARM_HRS:
|
||||
{
|
||||
BOOLEAN Afternoon = FALSE;
|
||||
BYTE Value = CmosMemory.AlarmHour;
|
||||
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value >= 12))
|
||||
{
|
||||
Value -= 12;
|
||||
Afternoon = TRUE;
|
||||
}
|
||||
|
||||
Value = READ_CMOS_DATA(CmosMemory, Value);
|
||||
|
||||
/* Convert to 12-hour */
|
||||
if (Afternoon) Value |= 0x80;
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
case CMOS_REG_DAY_OF_WEEK:
|
||||
/*
|
||||
* The CMOS value is 1-based but the
|
||||
* GetLocalTime API value is 0-based.
|
||||
* Correct it.
|
||||
*/
|
||||
return READ_CMOS_DATA(CmosMemory, CurrentTime.wDayOfWeek + 1);
|
||||
|
||||
case CMOS_REG_DAY:
|
||||
return READ_CMOS_DATA(CmosMemory, CurrentTime.wDay);
|
||||
|
||||
case CMOS_REG_MONTH:
|
||||
return READ_CMOS_DATA(CmosMemory, CurrentTime.wMonth);
|
||||
|
||||
case CMOS_REG_YEAR:
|
||||
return READ_CMOS_DATA(CmosMemory, CurrentTime.wYear % 100);
|
||||
|
||||
case CMOS_REG_STATUS_C:
|
||||
{
|
||||
BYTE Value = CmosMemory.StatusRegC;
|
||||
|
||||
/* Clear status register C */
|
||||
CmosMemory.StatusRegC = 0x00;
|
||||
|
||||
/* Return the old value */
|
||||
return Value;
|
||||
}
|
||||
|
||||
case CMOS_REG_STATUS_A:
|
||||
case CMOS_REG_STATUS_B:
|
||||
case CMOS_REG_STATUS_D:
|
||||
case CMOS_REG_DIAGNOSTICS:
|
||||
case CMOS_REG_SHUTDOWN_STATUS:
|
||||
default:
|
||||
{
|
||||
// ASSERT(SelectedRegister < CMOS_REG_MAX);
|
||||
return CmosMemory.Regs[SelectedRegister];
|
||||
}
|
||||
}
|
||||
|
||||
/* Return to Status Register D */
|
||||
SelectedRegister = CMOS_REG_STATUS_D;
|
||||
}
|
||||
|
||||
VOID CmosWriteData(BYTE Value)
|
||||
{
|
||||
BOOLEAN ChangeTime = FALSE;
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
||||
/* Get the current time */
|
||||
GetLocalTime(&CurrentTime);
|
||||
|
||||
switch (SelectedRegister)
|
||||
{
|
||||
case CMOS_REG_SECONDS:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wSecond = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_ALARM_SEC:
|
||||
{
|
||||
CmosMemory.AlarmSecond = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_MINUTES:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wMinute = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_ALARM_MIN:
|
||||
{
|
||||
CmosMemory.AlarmMinute = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_HOURS:
|
||||
{
|
||||
BOOLEAN Afternoon = FALSE;
|
||||
|
||||
ChangeTime = TRUE;
|
||||
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
|
||||
{
|
||||
Value &= ~0x80;
|
||||
Afternoon = TRUE;
|
||||
}
|
||||
|
||||
CurrentTime.wHour = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
|
||||
/* Convert to 24-hour format */
|
||||
if (Afternoon) CurrentTime.wHour += 12;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_ALARM_HRS:
|
||||
{
|
||||
BOOLEAN Afternoon = FALSE;
|
||||
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
|
||||
{
|
||||
Value &= ~0x80;
|
||||
Afternoon = TRUE;
|
||||
}
|
||||
|
||||
CmosMemory.AlarmHour = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
|
||||
/* Convert to 24-hour format */
|
||||
if (Afternoon) CmosMemory.AlarmHour += 12;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_DAY_OF_WEEK:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
/*
|
||||
* The CMOS value is 1-based but the
|
||||
* SetLocalTime API value is 0-based.
|
||||
* Correct it.
|
||||
*/
|
||||
Value -= 1;
|
||||
CurrentTime.wDayOfWeek = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_DAY:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wDay = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_MONTH:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wMonth = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_YEAR:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
|
||||
/* Clear everything except the century */
|
||||
CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
|
||||
|
||||
CurrentTime.wYear += WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_STATUS_A:
|
||||
{
|
||||
CmosMemory.StatusRegA = Value & 0x7F; // Bit 7 is read-only
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_STATUS_B:
|
||||
{
|
||||
CmosMemory.StatusRegB = Value;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_STATUS_C:
|
||||
case CMOS_REG_STATUS_D:
|
||||
// Status registers C and D are read-only
|
||||
break;
|
||||
|
||||
/* Is the following correct? */
|
||||
case CMOS_REG_EXT_MEMORY_LOW:
|
||||
case CMOS_REG_ACTUAL_EXT_MEMORY_LOW:
|
||||
{
|
||||
/* Sync EMS and UMS */
|
||||
CmosMemory.Regs[CMOS_REG_EXT_MEMORY_LOW] =
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = Value;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Is the following correct? */
|
||||
case CMOS_REG_EXT_MEMORY_HIGH:
|
||||
case CMOS_REG_ACTUAL_EXT_MEMORY_HIGH:
|
||||
{
|
||||
/* Sync EMS and UMS */
|
||||
CmosMemory.Regs[CMOS_REG_EXT_MEMORY_HIGH] =
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = Value;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
CmosMemory.Regs[SelectedRegister] = Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (ChangeTime) SetLocalTime(&CurrentTime);
|
||||
|
||||
/* Return to Status Register D */
|
||||
SelectedRegister = CMOS_REG_STATUS_D;
|
||||
}
|
||||
|
||||
BYTE WINAPI CmosReadPort(ULONG Port)
|
||||
{
|
||||
ASSERT(Port == CMOS_DATA_PORT);
|
||||
return CmosReadData();
|
||||
}
|
||||
|
||||
VOID WINAPI CmosWritePort(ULONG Port, BYTE Data)
|
||||
{
|
||||
if (Port == CMOS_ADDRESS_PORT)
|
||||
CmosWriteAddress(Data);
|
||||
else if (Port == CMOS_DATA_PORT)
|
||||
CmosWriteData(Data);
|
||||
}
|
||||
|
||||
DWORD RtcGetTicksPerSecond(VOID)
|
||||
{
|
||||
BYTE RateSelect = CmosMemory.StatusRegB & 0x0F;
|
||||
|
||||
if (RateSelect == 0)
|
||||
{
|
||||
/* No periodic interrupt */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 1 and 2 act like 8 and 9 */
|
||||
if (RateSelect <= 2) RateSelect += 7;
|
||||
|
||||
return 1 << (16 - RateSelect);
|
||||
}
|
||||
|
||||
VOID RtcPeriodicTick(VOID)
|
||||
{
|
||||
/* Set PF */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_PF;
|
||||
|
||||
/* Check if there should be an interrupt on a periodic timer tick */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_PERIODIC)
|
||||
{
|
||||
CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
|
||||
/* Interrupt! */
|
||||
PicInterruptRequest(RTC_IRQ_NUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
/* Should be called every second */
|
||||
VOID RtcTimeUpdate(VOID)
|
||||
{
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
||||
/* Get the current time */
|
||||
GetLocalTime(&CurrentTime);
|
||||
|
||||
/* Set UF */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_UF;
|
||||
|
||||
/* Check if the time matches the alarm time */
|
||||
if ((CurrentTime.wHour == CmosMemory.AlarmHour ) &&
|
||||
(CurrentTime.wMinute == CmosMemory.AlarmMinute) &&
|
||||
(CurrentTime.wSecond == CmosMemory.AlarmSecond))
|
||||
{
|
||||
/* Set the alarm flag */
|
||||
CmosMemory.StatusRegC |= CMOS_STC_AF;
|
||||
|
||||
/* Set IRQF if there should be an interrupt */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_ALARM) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
}
|
||||
|
||||
/* Check if there should be an interrupt on update */
|
||||
if (CmosMemory.StatusRegB & CMOS_STB_INT_ON_UPDATE) CmosMemory.StatusRegC |= CMOS_STC_IRQF;
|
||||
|
||||
if (CmosMemory.StatusRegC & CMOS_STC_IRQF)
|
||||
{
|
||||
/* Interrupt! */
|
||||
PicInterruptRequest(RTC_IRQ_NUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
VOID CmosInitialize(VOID)
|
||||
{
|
||||
DWORD CmosSize = sizeof(CmosMemory);
|
||||
|
||||
/* File must not be opened before */
|
||||
ASSERT(hCmosRam == INVALID_HANDLE_VALUE);
|
||||
|
||||
/* Clear the CMOS memory */
|
||||
ZeroMemory(&CmosMemory, sizeof(CmosMemory));
|
||||
|
||||
/* Always open (and if needed, create) a RAM file with shared access */
|
||||
SetLastError(0); // For debugging purposes
|
||||
hCmosRam = CreateFileW(L"cmos.ram",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
DPRINT1("CMOS opening %s ; GetLastError() = %u\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
|
||||
|
||||
if (hCmosRam != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
BOOL Success;
|
||||
|
||||
/* Attempt to fill the CMOS memory with the RAM file */
|
||||
SetLastError(0); // For debugging purposes
|
||||
Success = ReadFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
|
||||
if (CmosSize != sizeof(CmosMemory))
|
||||
{
|
||||
/* Bad CMOS Ram file. Reinitialize the CMOS memory. */
|
||||
DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n", CmosSize, sizeof(CmosMemory));
|
||||
ZeroMemory(&CmosMemory, sizeof(CmosMemory));
|
||||
}
|
||||
DPRINT1("CMOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
|
||||
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
|
||||
}
|
||||
|
||||
/* Overwrite some registers with default values */
|
||||
CmosMemory.StatusRegA = CMOS_DEFAULT_STA;
|
||||
CmosMemory.StatusRegB = CMOS_DEFAULT_STB;
|
||||
CmosMemory.StatusRegC = 0x00;
|
||||
CmosMemory.StatusRegD = CMOS_BATTERY_OK; // Our CMOS battery works perfectly forever.
|
||||
CmosMemory.Diagnostics = 0x00; // Diagnostics must not find any errors.
|
||||
CmosMemory.ShutdownStatus = 0x00;
|
||||
|
||||
/* Memory settings */
|
||||
|
||||
/*
|
||||
* Conventional memory size is 640 kB,
|
||||
* see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
|
||||
* and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
|
||||
* for more information.
|
||||
*/
|
||||
CmosMemory.Regs[CMOS_REG_BASE_MEMORY_LOW ] = LOBYTE(0x0280);
|
||||
CmosMemory.Regs[CMOS_REG_BASE_MEMORY_HIGH] = HIBYTE(0x0280);
|
||||
|
||||
CmosMemory.Regs[CMOS_REG_EXT_MEMORY_LOW] =
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = LOBYTE((MAX_ADDRESS - 0x100000) / 1024);
|
||||
|
||||
CmosMemory.Regs[CMOS_REG_EXT_MEMORY_HIGH] =
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = HIBYTE((MAX_ADDRESS - 0x100000) / 1024);
|
||||
|
||||
/* Register the I/O Ports */
|
||||
RegisterIoPort(CMOS_ADDRESS_PORT, NULL , CmosWritePort);
|
||||
RegisterIoPort(CMOS_DATA_PORT , CmosReadPort, CmosWritePort);
|
||||
}
|
||||
|
||||
VOID CmosCleanup(VOID)
|
||||
{
|
||||
DWORD CmosSize = sizeof(CmosMemory);
|
||||
|
||||
if (hCmosRam == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
/* Flush the CMOS memory back to the RAM file and close it */
|
||||
SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
|
||||
WriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
|
||||
|
||||
CloseHandle(hCmosRam);
|
||||
hCmosRam = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: cmos.h
|
||||
* PURPOSE: CMOS Real Time Clock emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _CMOS_H_
|
||||
#define _CMOS_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define RTC_IRQ_NUMBER 8
|
||||
#define CMOS_ADDRESS_PORT 0x70
|
||||
#define CMOS_DATA_PORT 0x71
|
||||
#define CMOS_DISABLE_NMI (1 << 7)
|
||||
#define CMOS_BATTERY_OK 0x80
|
||||
|
||||
/* Status Register B flags */
|
||||
#define CMOS_STB_24HOUR (1 << 1)
|
||||
#define CMOS_STB_BINARY (1 << 2)
|
||||
#define CMOS_STB_SQUARE_WAVE (1 << 3)
|
||||
#define CMOS_STB_INT_ON_UPDATE (1 << 4)
|
||||
#define CMOS_STB_INT_ON_ALARM (1 << 5)
|
||||
#define CMOS_STB_INT_PERIODIC (1 << 6)
|
||||
|
||||
/* Status Register C flags */
|
||||
#define CMOS_STC_UF CMOS_STB_INT_ON_UPDATE
|
||||
#define CMOS_STC_AF CMOS_STB_INT_ON_ALARM
|
||||
#define CMOS_STC_PF CMOS_STB_INT_PERIODIC
|
||||
#define CMOS_STC_IRQF (1 << 7)
|
||||
|
||||
/* Default register values */
|
||||
#define CMOS_DEFAULT_STA 0x26
|
||||
#define CMOS_DEFAULT_STB CMOS_STB_24HOUR
|
||||
|
||||
#define WRITE_CMOS_DATA(Cmos, Value) \
|
||||
((Cmos).StatusRegB & CMOS_STB_BINARY) ? (Value) : BCD_TO_BINARY(Value)
|
||||
|
||||
#define READ_CMOS_DATA(Cmos, Value) \
|
||||
((Cmos).StatusRegB & CMOS_STB_BINARY) ? (Value) : BINARY_TO_BCD(Value)
|
||||
|
||||
typedef enum _CMOS_REGISTERS
|
||||
{
|
||||
CMOS_REG_SECONDS,
|
||||
CMOS_REG_ALARM_SEC,
|
||||
CMOS_REG_MINUTES,
|
||||
CMOS_REG_ALARM_MIN,
|
||||
CMOS_REG_HOURS,
|
||||
CMOS_REG_ALARM_HRS,
|
||||
CMOS_REG_DAY_OF_WEEK,
|
||||
CMOS_REG_DAY,
|
||||
CMOS_REG_MONTH,
|
||||
CMOS_REG_YEAR,
|
||||
CMOS_REG_STATUS_A,
|
||||
CMOS_REG_STATUS_B,
|
||||
CMOS_REG_STATUS_C,
|
||||
CMOS_REG_STATUS_D,
|
||||
CMOS_REG_DIAGNOSTICS,
|
||||
CMOS_REG_SHUTDOWN_STATUS,
|
||||
CMOS_REG_BASE_MEMORY_LOW = 0x15,
|
||||
CMOS_REG_BASE_MEMORY_HIGH = 0x16,
|
||||
CMOS_REG_EXT_MEMORY_LOW = 0x17,
|
||||
CMOS_REG_EXT_MEMORY_HIGH = 0x18,
|
||||
CMOS_REG_ACTUAL_EXT_MEMORY_LOW = 0x30,
|
||||
CMOS_REG_ACTUAL_EXT_MEMORY_HIGH = 0x31,
|
||||
CMOS_REG_MAX = 0x40
|
||||
} CMOS_REGISTERS, *PCMOS_REGISTERS;
|
||||
|
||||
/*
|
||||
* CMOS Memory Map
|
||||
*
|
||||
* See the following documentation for more information:
|
||||
* http://www.intel-assembler.it/portale/5/cmos-memory-map-123/cmos-memory-map-123.asp
|
||||
* http://wiki.osdev.org/CMOS
|
||||
* http://www.walshcomptech.com/ohlandl/config/cmos_registers.html
|
||||
* http://www.fysnet.net/cmosinfo.htm
|
||||
* http://www.bioscentral.com/misc/cmosmap.htm
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
BYTE Second; // 0x00
|
||||
BYTE AlarmSecond; // 0x01
|
||||
BYTE Minute; // 0x02
|
||||
BYTE AlarmMinute; // 0x03
|
||||
BYTE Hour; // 0x04
|
||||
BYTE AlarmHour; // 0x05
|
||||
BYTE DayOfWeek; // 0x06
|
||||
BYTE Day; // 0x07
|
||||
BYTE Month; // 0x08
|
||||
BYTE Year; // 0x09
|
||||
|
||||
BYTE StatusRegA; // 0x0a
|
||||
BYTE StatusRegB; // 0x0b
|
||||
} CMOS_CLOCK, *PCMOS_CLOCK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
CMOS_CLOCK; // 0x00 - 0x0b
|
||||
BYTE StatusRegC; // 0x0c
|
||||
BYTE StatusRegD; // 0x0d
|
||||
BYTE Diagnostics; // 0x0e
|
||||
BYTE ShutdownStatus; // 0x0f
|
||||
};
|
||||
BYTE Regs1[0x10]; // 0x00 - 0x0f
|
||||
BYTE Regs [0x40]; // 0x00 - 0x3f
|
||||
};
|
||||
|
||||
/*
|
||||
* Extended information 0x40 - 0x7f
|
||||
*/
|
||||
} CMOS_MEMORY, *PCMOS_MEMORY;
|
||||
#pragma pack(pop)
|
||||
|
||||
C_ASSERT(sizeof(CMOS_MEMORY) == 0x40);
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN IsNmiEnabled(VOID);
|
||||
DWORD RtcGetTicksPerSecond(VOID);
|
||||
VOID RtcPeriodicTick(VOID);
|
||||
VOID RtcTimeUpdate(VOID);
|
||||
|
||||
VOID CmosInitialize(VOID);
|
||||
VOID CmosCleanup(VOID);
|
||||
|
||||
#endif // _CMOS_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: pic.c
|
||||
* PURPOSE: Programmable Interrupt Controller emulation
|
||||
* (Interrupt Controller Adapter (ICA) in Windows terminology)
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static PIC MasterPic, SlavePic;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static BYTE PicReadCommand(BYTE Port)
|
||||
{
|
||||
PPIC Pic;
|
||||
|
||||
/* Which PIC are we accessing? */
|
||||
if (Port == PIC_MASTER_CMD) Pic = &MasterPic;
|
||||
else Pic = &SlavePic;
|
||||
|
||||
if (Pic->ReadIsr)
|
||||
{
|
||||
/* Read the in-service register */
|
||||
Pic->ReadIsr = FALSE;
|
||||
return Pic->InServiceRegister;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read the interrupt request register */
|
||||
return Pic->IntRequestRegister;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID PicWriteCommand(BYTE Port, BYTE Value)
|
||||
{
|
||||
PPIC Pic;
|
||||
|
||||
/* Which PIC are we accessing? */
|
||||
if (Port == PIC_MASTER_CMD) Pic = &MasterPic;
|
||||
else Pic = &SlavePic;
|
||||
|
||||
if (Value & PIC_ICW1)
|
||||
{
|
||||
/* Start initialization */
|
||||
Pic->Initialization = TRUE;
|
||||
Pic->IntOffset = 0xFF;
|
||||
Pic->CascadeRegisterSet = FALSE;
|
||||
Pic->ConfigRegister = Value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Value & PIC_OCW3)
|
||||
{
|
||||
/* This is an OCR3 */
|
||||
if (Value == PIC_OCW3_READ_ISR)
|
||||
{
|
||||
/* Return the ISR on next read from command port */
|
||||
Pic->ReadIsr = TRUE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is an OCW2 */
|
||||
if (Value & PIC_OCW2_EOI)
|
||||
{
|
||||
if (Value & PIC_OCW2_SL)
|
||||
{
|
||||
/* If the SL bit is set, clear a specific IRQ */
|
||||
Pic->InServiceRegister &= ~(1 << (Value & PIC_OCW2_NUM_MASK));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, clear all of them */
|
||||
Pic->InServiceRegister = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE PicReadData(BYTE Port)
|
||||
{
|
||||
/* Read the mask register */
|
||||
if (Port == PIC_MASTER_DATA) return MasterPic.MaskRegister;
|
||||
else return SlavePic.MaskRegister;
|
||||
}
|
||||
|
||||
static VOID PicWriteData(BYTE Port, BYTE Value)
|
||||
{
|
||||
PPIC Pic;
|
||||
|
||||
/* Which PIC are we accessing? */
|
||||
if (Port == PIC_MASTER_DATA) Pic = &MasterPic;
|
||||
else Pic = &SlavePic;
|
||||
|
||||
/* Is the PIC ready? */
|
||||
if (!Pic->Initialization)
|
||||
{
|
||||
/* Yes, this is an OCW1 */
|
||||
Pic->MaskRegister = Value;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Has the interrupt offset been set? */
|
||||
if (Pic->IntOffset == 0xFF)
|
||||
{
|
||||
/* This is an ICW2, set the offset (last three bits always zero) */
|
||||
Pic->IntOffset = Value & 0xF8;
|
||||
|
||||
/* Check if we are in single mode and don't need an ICW4 */
|
||||
if ((Pic->ConfigRegister & PIC_ICW1_SINGLE)
|
||||
&& !(Pic->ConfigRegister & PIC_ICW1_ICW4))
|
||||
{
|
||||
/* Yes, done initializing */
|
||||
Pic->Initialization = FALSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we are in cascade mode and the cascade register was not set */
|
||||
if (!(Pic->ConfigRegister & PIC_ICW1_SINGLE) && !Pic->CascadeRegisterSet)
|
||||
{
|
||||
/* This is an ICW3 */
|
||||
Pic->CascadeRegister = Value;
|
||||
Pic->CascadeRegisterSet = TRUE;
|
||||
|
||||
/* Check if we need an ICW4 */
|
||||
if (!(Pic->ConfigRegister & PIC_ICW1_ICW4))
|
||||
{
|
||||
/* No, done initializing */
|
||||
Pic->Initialization = FALSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* This must be an ICW4, we will ignore the 8086 bit (assume always set) */
|
||||
if (Value & PIC_ICW4_AEOI)
|
||||
{
|
||||
/* Use automatic end-of-interrupt */
|
||||
Pic->AutoEoi = TRUE;
|
||||
}
|
||||
|
||||
/* Done initializing */
|
||||
Pic->Initialization = FALSE;
|
||||
}
|
||||
|
||||
static BYTE WINAPI PicReadPort(ULONG Port)
|
||||
{
|
||||
switch (Port)
|
||||
{
|
||||
case PIC_MASTER_CMD:
|
||||
case PIC_SLAVE_CMD:
|
||||
{
|
||||
return PicReadCommand(Port);
|
||||
}
|
||||
|
||||
case PIC_MASTER_DATA:
|
||||
case PIC_SLAVE_DATA:
|
||||
{
|
||||
return PicReadData(Port);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID WINAPI PicWritePort(ULONG Port, BYTE Data)
|
||||
{
|
||||
switch (Port)
|
||||
{
|
||||
case PIC_MASTER_CMD:
|
||||
case PIC_SLAVE_CMD:
|
||||
{
|
||||
PicWriteCommand(Port, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PIC_MASTER_DATA:
|
||||
case PIC_SLAVE_DATA:
|
||||
{
|
||||
PicWriteData(Port, Data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID PicInterruptRequest(BYTE Number)
|
||||
{
|
||||
BYTE i;
|
||||
|
||||
if (/* Number >= 0 && */ Number < 8)
|
||||
{
|
||||
/* Check if any of the higher-priority interrupts are busy */
|
||||
for (i = 0; i <= Number; i++)
|
||||
{
|
||||
if (MasterPic.InServiceRegister & (1 << Number)) return;
|
||||
}
|
||||
|
||||
/* Check if the interrupt is masked */
|
||||
if (MasterPic.MaskRegister & (1 << Number)) return;
|
||||
|
||||
/* Set the appropriate bit in the IRR and interrupt the CPU */
|
||||
MasterPic.IntRequestRegister |= 1 << Number;
|
||||
EmulatorInterruptSignal();
|
||||
}
|
||||
else if (Number >= 8 && Number < 16)
|
||||
{
|
||||
Number -= 8;
|
||||
|
||||
/*
|
||||
* The slave PIC is connected to IRQ 2, always! If the master PIC
|
||||
* was misconfigured, don't do anything.
|
||||
*/
|
||||
if (!(MasterPic.CascadeRegister & (1 << 2))
|
||||
|| SlavePic.CascadeRegister != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if any of the higher-priority interrupts are busy */
|
||||
if (MasterPic.InServiceRegister != 0) return;
|
||||
for (i = 0; i <= Number; i++)
|
||||
{
|
||||
if (SlavePic.InServiceRegister & (1 << Number)) return;
|
||||
}
|
||||
|
||||
/* Check if the interrupt is masked */
|
||||
if (SlavePic.MaskRegister & (1 << Number)) return;
|
||||
|
||||
/* Set the IRQ 2 bit in the master ISR */
|
||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << 2);
|
||||
|
||||
/* Set the appropriate bit in the IRR and interrupt the CPU */
|
||||
SlavePic.IntRequestRegister |= 1 << Number;
|
||||
EmulatorInterruptSignal();
|
||||
}
|
||||
}
|
||||
|
||||
BYTE PicGetInterrupt(VOID)
|
||||
{
|
||||
INT i, j;
|
||||
|
||||
/* Search interrupts by priority */
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
/* Check if this line is cascaded to the slave PIC */
|
||||
if ((i == 2)
|
||||
&& MasterPic.CascadeRegister & (1 << 2)
|
||||
&& SlavePic.Slave
|
||||
&& (SlavePic.CascadeRegister == 2))
|
||||
{
|
||||
/* Search the slave PIC interrupts by priority */
|
||||
for (j = 0; j < 8; j++) if ((j != 1) && SlavePic.IntRequestRegister & (1 << j))
|
||||
{
|
||||
/* Clear the IRR flag */
|
||||
SlavePic.IntRequestRegister &= ~(1 << j);
|
||||
|
||||
/* Set the ISR flag, unless AEOI is enabled */
|
||||
if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= (1 << j);
|
||||
|
||||
/* Return the interrupt number */
|
||||
return SlavePic.IntOffset + j;
|
||||
}
|
||||
}
|
||||
|
||||
if (MasterPic.IntRequestRegister & (1 << i))
|
||||
{
|
||||
/* Clear the IRR flag */
|
||||
MasterPic.IntRequestRegister &= ~(1 << i);
|
||||
|
||||
/* Set the ISR flag, unless AEOI is enabled */
|
||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << i);
|
||||
|
||||
/* Return the interrupt number */
|
||||
return MasterPic.IntOffset + i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Spurious interrupt */
|
||||
if (MasterPic.InServiceRegister & (1 << 2)) return SlavePic.IntOffset + 7;
|
||||
else return MasterPic.IntOffset + 7;
|
||||
}
|
||||
|
||||
VOID PicInitialize(VOID)
|
||||
{
|
||||
/* Register the I/O Ports */
|
||||
RegisterIoPort(PIC_MASTER_CMD , PicReadPort, PicWritePort);
|
||||
RegisterIoPort(PIC_SLAVE_CMD , PicReadPort, PicWritePort);
|
||||
RegisterIoPort(PIC_MASTER_DATA, PicReadPort, PicWritePort);
|
||||
RegisterIoPort(PIC_SLAVE_DATA , PicReadPort, PicWritePort);
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
call_ica_hw_interrupt(INT ms,
|
||||
BYTE line,
|
||||
INT count)
|
||||
{
|
||||
BYTE InterruptNumber = line;
|
||||
|
||||
/* Check for PIC validity */
|
||||
if (ms != ICA_MASTER || ms != ICA_SLAVE) return;
|
||||
|
||||
/*
|
||||
* Adjust the interrupt request number according to the parameters,
|
||||
* by adding an offset == 8 to the interrupt number.
|
||||
*
|
||||
* Indeed VDDs calling this function usually subtracts 8 so that they give:
|
||||
*
|
||||
* ms | line | corresponding interrupt number
|
||||
* ------------+--------+--------------------------------
|
||||
* ICA_MASTER | 0 -- 7 | 0 -- 7
|
||||
* ICA_SLAVE | 0 -- 7 | 8 -- 15
|
||||
*
|
||||
* and PicInterruptRequest subtracts again 8 to the interrupt number
|
||||
* if it is greater or equal than 8 (so that it determines which PIC
|
||||
* to use via the interrupt number).
|
||||
*/
|
||||
if (ms == ICA_SLAVE) InterruptNumber += 8;
|
||||
|
||||
/* Send the specified number of interrupt requests */
|
||||
while (count-- > 0)
|
||||
{
|
||||
PicInterruptRequest(InterruptNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: pic.h
|
||||
* PURPOSE: Programmable Interrupt Controller emulation
|
||||
* (Interrupt Controller Adapter (ICA) in Windows terminology)
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _PIC_H_
|
||||
#define _PIC_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define PIC_MASTER_CMD 0x20
|
||||
#define PIC_MASTER_DATA 0x21
|
||||
#define PIC_SLAVE_CMD 0xA0
|
||||
#define PIC_SLAVE_DATA 0xA1
|
||||
|
||||
#define PIC_ICW1 0x10
|
||||
#define PIC_ICW1_ICW4 (1 << 0)
|
||||
#define PIC_ICW1_SINGLE (1 << 1)
|
||||
#define PIC_ICW4_8086 (1 << 0)
|
||||
#define PIC_ICW4_AEOI (1 << 1)
|
||||
|
||||
#define PIC_OCW2_NUM_MASK 0x07
|
||||
#define PIC_OCW2_EOI (1 << 5)
|
||||
#define PIC_OCW2_SL (1 << 6)
|
||||
|
||||
#define PIC_OCW3 (1 << 3)
|
||||
#define PIC_OCW3_READ_ISR 0x0B
|
||||
|
||||
typedef struct _PIC
|
||||
{
|
||||
BOOLEAN Initialization;
|
||||
BYTE MaskRegister;
|
||||
BYTE IntRequestRegister;
|
||||
BYTE InServiceRegister;
|
||||
BYTE IntOffset;
|
||||
BYTE ConfigRegister;
|
||||
BYTE CascadeRegister;
|
||||
BOOLEAN CascadeRegisterSet;
|
||||
BOOLEAN AutoEoi;
|
||||
BOOLEAN Slave;
|
||||
BOOLEAN ReadIsr;
|
||||
} PIC, *PPIC;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID PicInterruptRequest(BYTE Number);
|
||||
BYTE PicGetInterrupt(VOID);
|
||||
|
||||
VOID PicInitialize(VOID);
|
||||
|
||||
#endif // _PIC_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: ps2.c
|
||||
* PURPOSE: PS/2 controller emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "io.h"
|
||||
#include "ps2.h"
|
||||
#include "pic.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BYTE KeyboardQueue[KEYBOARD_BUFFER_SIZE];
|
||||
static BOOLEAN KeyboardQueueEmpty = TRUE;
|
||||
static UINT KeyboardQueueStart = 0;
|
||||
static UINT KeyboardQueueEnd = 0;
|
||||
static BYTE KeyboardData = 0, KeyboardResponse = 0;
|
||||
static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE;
|
||||
static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG;
|
||||
static HANDLE QueueMutex = NULL;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static BOOLEAN KeyboardQueuePush(BYTE ScanCode)
|
||||
{
|
||||
BOOLEAN Result = TRUE;
|
||||
|
||||
WaitForSingleObject(QueueMutex, INFINITE);
|
||||
|
||||
/* Check if the keyboard queue is full */
|
||||
if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd))
|
||||
{
|
||||
Result = FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* Insert the value in the queue */
|
||||
KeyboardQueue[KeyboardQueueEnd] = ScanCode;
|
||||
KeyboardQueueEnd++;
|
||||
KeyboardQueueEnd %= KEYBOARD_BUFFER_SIZE;
|
||||
|
||||
/* Since we inserted a value, it's not empty anymore */
|
||||
KeyboardQueueEmpty = FALSE;
|
||||
|
||||
Done:
|
||||
ReleaseMutex(QueueMutex);
|
||||
return Result;
|
||||
}
|
||||
|
||||
static BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
|
||||
{
|
||||
BOOLEAN Result = TRUE;
|
||||
|
||||
/* Make sure the keyboard queue is not empty (fast check) */
|
||||
if (KeyboardQueueEmpty) return FALSE;
|
||||
|
||||
WaitForSingleObject(QueueMutex, INFINITE);
|
||||
|
||||
/*
|
||||
* Recheck whether keyboard queue is not empty (it
|
||||
* may have changed after having grabbed the mutex).
|
||||
*/
|
||||
if (KeyboardQueueEmpty)
|
||||
{
|
||||
Result = FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* Get the scan code */
|
||||
*ScanCode = KeyboardQueue[KeyboardQueueStart];
|
||||
|
||||
/* Remove the value from the queue */
|
||||
KeyboardQueueStart++;
|
||||
KeyboardQueueStart %= KEYBOARD_BUFFER_SIZE;
|
||||
|
||||
/* Check if the queue is now empty */
|
||||
if (KeyboardQueueStart == KeyboardQueueEnd)
|
||||
{
|
||||
KeyboardQueueEmpty = TRUE;
|
||||
}
|
||||
|
||||
Done:
|
||||
ReleaseMutex(QueueMutex);
|
||||
return Result;
|
||||
}
|
||||
|
||||
static BYTE WINAPI PS2ReadPort(ULONG Port)
|
||||
{
|
||||
if (Port == PS2_CONTROL_PORT)
|
||||
{
|
||||
BYTE Status = 0;
|
||||
|
||||
/* Set the first bit if the data can be read */
|
||||
if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0;
|
||||
|
||||
/* Always set bit 2 */
|
||||
Status |= 1 << 2;
|
||||
|
||||
/* Set bit 3 if the next byte goes to the controller */
|
||||
if (KeyboardWriteResponse) Status |= 1 << 3;
|
||||
|
||||
return Status;
|
||||
}
|
||||
else if (Port == PS2_DATA_PORT)
|
||||
{
|
||||
/* If there was a response byte from the controller, return it */
|
||||
if (KeyboardReadResponse)
|
||||
{
|
||||
KeyboardReadResponse = FALSE;
|
||||
KeyboardData = KeyboardResponse;
|
||||
}
|
||||
|
||||
return KeyboardData;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
|
||||
{
|
||||
if (Port == PS2_CONTROL_PORT)
|
||||
{
|
||||
switch (Data)
|
||||
{
|
||||
/* Read configuration byte */
|
||||
case 0x20:
|
||||
{
|
||||
KeyboardResponse = KeyboardConfig;
|
||||
KeyboardReadResponse = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write configuration byte */
|
||||
case 0x60:
|
||||
/* Write controller output port */
|
||||
case 0xD1:
|
||||
/* Write keyboard output buffer */
|
||||
case 0xD2:
|
||||
/* Write mouse output buffer */
|
||||
case 0xD3:
|
||||
/* Write mouse input buffer */
|
||||
case 0xD4:
|
||||
{
|
||||
/* These commands require a response */
|
||||
KeyboardResponse = Data;
|
||||
KeyboardWriteResponse = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable mouse */
|
||||
case 0xA7:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable mouse */
|
||||
case 0xA8:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test mouse port */
|
||||
case 0xA9:
|
||||
{
|
||||
KeyboardResponse = 0;
|
||||
KeyboardReadResponse = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test PS/2 controller */
|
||||
case 0xAA:
|
||||
{
|
||||
KeyboardResponse = 0x55;
|
||||
KeyboardReadResponse = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable keyboard */
|
||||
case 0xAD:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable keyboard */
|
||||
case 0xAE:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read controller output port */
|
||||
case 0xD0:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
break;
|
||||
}
|
||||
|
||||
/* CPU Reset */
|
||||
case 0xF0:
|
||||
case 0xF2:
|
||||
case 0xF4:
|
||||
case 0xF6:
|
||||
case 0xF8:
|
||||
case 0xFA:
|
||||
case 0xFC:
|
||||
case 0xFE:
|
||||
{
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Port == PS2_DATA_PORT)
|
||||
{
|
||||
/* Check if the controller is waiting for a response */
|
||||
if (KeyboardWriteResponse)
|
||||
{
|
||||
KeyboardWriteResponse = FALSE;
|
||||
|
||||
/* Check which command it was */
|
||||
switch (KeyboardResponse)
|
||||
{
|
||||
/* Write configuration byte */
|
||||
case 0x60:
|
||||
{
|
||||
KeyboardConfig = Data;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write controller output */
|
||||
case 0xD1:
|
||||
{
|
||||
/* Check if bit 0 is unset */
|
||||
if (!(Data & (1 << 0)))
|
||||
{
|
||||
/* CPU disabled - Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
}
|
||||
|
||||
/* Update the A20 line setting */
|
||||
EmulatorSetA20(Data & (1 << 1));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xD2:
|
||||
{
|
||||
/* Push the data byte to the keyboard queue */
|
||||
KeyboardQueuePush(Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xD3:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xD4:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Implement PS/2 device commands
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID PS2Dispatch(PINPUT_RECORD InputRecord)
|
||||
{
|
||||
/* Check the event type */
|
||||
switch (InputRecord->EventType)
|
||||
{
|
||||
case KEY_EVENT:
|
||||
{
|
||||
WORD i;
|
||||
BYTE ScanCode = (BYTE)InputRecord->Event.KeyEvent.wVirtualScanCode;
|
||||
|
||||
/* If this is a key release, set the highest bit in the scan code */
|
||||
if (!InputRecord->Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
|
||||
|
||||
/* Push the scan code onto the keyboard queue */
|
||||
for (i = 0; i < InputRecord->Event.KeyEvent.wRepeatCount; i++)
|
||||
{
|
||||
KeyboardQueuePush(ScanCode);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MOUSE_EVENT:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
UNIMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We ignore all the rest */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VOID GenerateKeyboardInterrupts(VOID)
|
||||
{
|
||||
/* Generate an IRQ 1 if there is a key ready in the queue */
|
||||
if (KeyboardQueuePop(&KeyboardData)) PicInterruptRequest(1);
|
||||
}
|
||||
|
||||
BOOLEAN PS2Initialize(HANDLE ConsoleInput)
|
||||
{
|
||||
#if 0
|
||||
DWORD ConInMode;
|
||||
#endif
|
||||
|
||||
/* Create the mutex */
|
||||
QueueMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
/* Register the I/O Ports */
|
||||
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
|
||||
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
|
||||
|
||||
#if 0
|
||||
if (GetConsoleMode(ConsoleInput, &ConInMode))
|
||||
{
|
||||
if (MousePresent)
|
||||
{
|
||||
/* Support mouse input events if there is a mouse on the system */
|
||||
ConInMode |= ENABLE_MOUSE_INPUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do not support mouse input events if there is no mouse on the system */
|
||||
ConInMode &= ~ENABLE_MOUSE_INPUT;
|
||||
}
|
||||
|
||||
SetConsoleMode(ConsoleInput, ConInMode);
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID PS2Cleanup(VOID)
|
||||
{
|
||||
CloseHandle(QueueMutex);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: ps2.h
|
||||
* PURPOSE: PS/2 controller emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _PS2_H_
|
||||
#define _PS2_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define KEYBOARD_BUFFER_SIZE 32
|
||||
#define PS2_DATA_PORT 0x60
|
||||
#define PS2_CONTROL_PORT 0x64
|
||||
#define PS2_DEFAULT_CONFIG 0x05
|
||||
#define KEYBOARD_ACK 0xFA
|
||||
#define KEYBOARD_RESEND 0xFE
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID PS2Dispatch(PINPUT_RECORD InputRecord);
|
||||
VOID GenerateKeyboardInterrupts(VOID);
|
||||
|
||||
BOOLEAN PS2Initialize(HANDLE ConsoleInput);
|
||||
VOID PS2Cleanup(VOID);
|
||||
|
||||
#endif // _PS2_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: speaker.c
|
||||
* PURPOSE: PC Speaker emulation
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "speaker.h"
|
||||
#include "io.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* Extra PSDK/NDK Headers */
|
||||
#include <ndk/iofuncs.h>
|
||||
#include <ndk/obfuncs.h>
|
||||
#include <ndk/rtlfuncs.h>
|
||||
|
||||
/* DDK Driver Headers */
|
||||
#include <ntddbeep.h>
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static HANDLE hBeep = NULL;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID SpeakerChange(VOID)
|
||||
{
|
||||
BYTE Port61hState = IOReadB(CONTROL_SYSTEM_PORT61H);
|
||||
BOOLEAN IsConnectedToPITChannel2 = !!(Port61hState & 0x01);
|
||||
BOOLEAN SpeakerDataOn = !!(Port61hState & 0x02);
|
||||
|
||||
if (PitChannel2 && IsConnectedToPITChannel2 && SpeakerDataOn)
|
||||
{
|
||||
/* Start beeping - Adapted from kernel32:Beep() */
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
BEEP_SET_PARAMETERS BeepSetParameters;
|
||||
|
||||
DWORD PitChannel2ReloadValue = PitChannel2->ReloadValue;
|
||||
if (PitChannel2ReloadValue == 0) PitChannel2ReloadValue = 65536;
|
||||
|
||||
/* Set beep data */
|
||||
BeepSetParameters.Frequency = (PIT_BASE_FREQUENCY / PitChannel2ReloadValue) *
|
||||
(PitChannel2->Mode == PIT_MODE_SQUARE_WAVE ? 2 : 1);
|
||||
BeepSetParameters.Duration = INFINITE;
|
||||
|
||||
/* Send the beep */
|
||||
Status = NtDeviceIoControlFile(hBeep,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
IOCTL_BEEP_SET,
|
||||
&BeepSetParameters,
|
||||
sizeof(BeepSetParameters),
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
|
||||
BeepSetParameters.Frequency,
|
||||
BeepSetParameters.Duration,
|
||||
Status);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop beeping */
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
BEEP_SET_PARAMETERS BeepSetParameters;
|
||||
|
||||
/* Set beep data */
|
||||
BeepSetParameters.Frequency = 0x00;
|
||||
BeepSetParameters.Duration = 0x00;
|
||||
|
||||
/* Send the beep */
|
||||
Status = NtDeviceIoControlFile(hBeep,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
IOCTL_BEEP_SET,
|
||||
&BeepSetParameters,
|
||||
sizeof(BeepSetParameters),
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
|
||||
BeepSetParameters.Frequency,
|
||||
BeepSetParameters.Duration,
|
||||
Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID SpeakerInitialize(VOID)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING BeepDevice;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
/* Adapted from kernel32:Beep() */
|
||||
|
||||
//
|
||||
// On TS systems, we need to Load Winsta.dll and call WinstationBeepOpen
|
||||
// after doing a GetProcAddress for it
|
||||
//
|
||||
|
||||
/* Open the device */
|
||||
RtlInitUnicodeString(&BeepDevice, L"\\Device\\Beep");
|
||||
InitializeObjectAttributes(&ObjectAttributes, &BeepDevice, 0, NULL, NULL);
|
||||
Status = NtCreateFile(&hBeep,
|
||||
FILE_READ_DATA | FILE_WRITE_DATA,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_OPEN_IF,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to open Beep driver, Status 0x%08lx\n", Status);
|
||||
}
|
||||
}
|
||||
|
||||
VOID SpeakerCleanup(VOID)
|
||||
{
|
||||
NtClose(hBeep);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: speaker.h
|
||||
* PURPOSE: PC Speaker emulation
|
||||
* PROGRAMMERS: Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _SPEAKER_H_
|
||||
#define _SPEAKER_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID SpeakerChange(VOID);
|
||||
|
||||
VOID SpeakerInitialize(VOID);
|
||||
VOID SpeakerCleanup(VOID);
|
||||
|
||||
#endif // _SPEAKER_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: timer.c
|
||||
* PURPOSE: Programmable Interval Timer emulation -
|
||||
* i82C54/8254 compatible
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "io.h"
|
||||
#include "timer.h"
|
||||
#include "pic.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static PIT_CHANNEL PitChannels[PIT_CHANNELS];
|
||||
PPIT_CHANNEL PitChannel2 = &PitChannels[2];
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID PitLatchChannelStatus(BYTE Channel)
|
||||
{
|
||||
if (Channel >= PIT_CHANNELS) return;
|
||||
|
||||
/*
|
||||
* A given counter can be latched only one time until it gets unlatched.
|
||||
* If the counter is latched and then is latched again later before the
|
||||
* value is read, then this last latch command is ignored and the value
|
||||
* will be the value at the time the first command was issued.
|
||||
*/
|
||||
if (PitChannels[Channel].LatchStatusSet == FALSE)
|
||||
{
|
||||
BYTE StatusLatch = 0;
|
||||
/** HACK!! **/BYTE NullCount = 0;/** HACK!! **/
|
||||
|
||||
StatusLatch = PitChannels[Channel].Out << 7 | NullCount << 6;
|
||||
StatusLatch |= (PitChannels[Channel].ReadWriteMode & 0x03) << 4;
|
||||
StatusLatch |= (PitChannels[Channel].Mode & 0x07) << 1;
|
||||
StatusLatch |= (PitChannels[Channel].Bcd & 0x01);
|
||||
|
||||
/* Latch the counter's status */
|
||||
PitChannels[Channel].LatchStatusSet = TRUE;
|
||||
PitChannels[Channel].StatusLatch = StatusLatch;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID PitLatchChannelCount(BYTE Channel)
|
||||
{
|
||||
if (Channel >= PIT_CHANNELS) return;
|
||||
|
||||
/*
|
||||
* A given counter can be latched only one time until it gets unlatched.
|
||||
* If the counter is latched and then is latched again later before the
|
||||
* value is read, then this last latch command is ignored and the value
|
||||
* will be the value at the time the first command was issued.
|
||||
*/
|
||||
if (PitChannels[Channel].ReadStatus == 0x00)
|
||||
{
|
||||
/* Latch the counter's value */
|
||||
PitChannels[Channel].ReadStatus = PitChannels[Channel].ReadWriteMode;
|
||||
|
||||
/* Convert the current value to BCD if needed */
|
||||
PitChannels[Channel].OutputLatch =
|
||||
READ_PIT_VALUE(PitChannels[Channel], PitChannels[Channel].CurrentValue);
|
||||
}
|
||||
}
|
||||
|
||||
static VOID PitSetOut(PPIT_CHANNEL Channel, BOOLEAN State)
|
||||
{
|
||||
/** HACK!! **\ if (State == Channel->Out) return; \** HACK!! **/
|
||||
|
||||
/* Set the new state of the OUT pin */
|
||||
Channel->Out = State;
|
||||
|
||||
/* Call the callback */
|
||||
if (Channel->OutFunction) Channel->OutFunction(Channel->OutParam, State);
|
||||
}
|
||||
|
||||
static VOID PitInitCounter(PPIT_CHANNEL Channel)
|
||||
{
|
||||
switch (Channel->Mode)
|
||||
{
|
||||
case PIT_MODE_INT_ON_TERMINAL_COUNT:
|
||||
PitSetOut(Channel, FALSE);
|
||||
break;
|
||||
|
||||
case PIT_MODE_HARDWARE_ONE_SHOT:
|
||||
case PIT_MODE_RATE_GENERATOR:
|
||||
case PIT_MODE_SQUARE_WAVE:
|
||||
case PIT_MODE_SOFTWARE_STROBE:
|
||||
case PIT_MODE_HARDWARE_STROBE:
|
||||
PitSetOut(Channel, TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID PitWriteCommand(BYTE Value)
|
||||
{
|
||||
BYTE Channel = (Value >> 6) & 0x03;
|
||||
BYTE ReadWriteMode = (Value >> 4) & 0x03;
|
||||
BYTE Mode = (Value >> 1) & 0x07;
|
||||
BOOLEAN IsBcd = Value & 0x01;
|
||||
|
||||
/*
|
||||
* Check for valid PIT channel - Possible values: 0, 1, 2.
|
||||
* A value of 3 is for Read-Back Command.
|
||||
*/
|
||||
if (Channel > PIT_CHANNELS) return;
|
||||
|
||||
/* Read-Back Command */
|
||||
if (Channel == PIT_CHANNELS)
|
||||
{
|
||||
if ((Value & 0x20) == 0) // Bit 5 (Count) == 0: We latch multiple counters' counts
|
||||
{
|
||||
if (Value & 0x02) PitLatchChannelCount(0);
|
||||
if (Value & 0x04) PitLatchChannelCount(1);
|
||||
if (Value & 0x08) PitLatchChannelCount(2);
|
||||
}
|
||||
if ((Value & 0x10) == 0) // Bit 4 (Status) == 0: We latch multiple counters' statuses
|
||||
{
|
||||
if (Value & 0x02) PitLatchChannelStatus(0);
|
||||
if (Value & 0x04) PitLatchChannelStatus(1);
|
||||
if (Value & 0x08) PitLatchChannelStatus(2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if this is a counter latch command... */
|
||||
if (ReadWriteMode == 0)
|
||||
{
|
||||
PitLatchChannelCount(Channel);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ... otherwise, set the modes and reset flip-flops */
|
||||
PitChannels[Channel].ReadWriteMode = ReadWriteMode;
|
||||
PitChannels[Channel].ReadStatus = 0x00;
|
||||
PitChannels[Channel].WriteStatus = 0x00;
|
||||
|
||||
PitChannels[Channel].LatchStatusSet = FALSE;
|
||||
PitChannels[Channel].StatusLatch = 0x00;
|
||||
|
||||
PitChannels[Channel].CountRegister = 0x00;
|
||||
PitChannels[Channel].OutputLatch = 0x00;
|
||||
|
||||
/** HACK!! **/PitChannels[Channel].FlipFlop = FALSE;/** HACK!! **/
|
||||
|
||||
/* Fix the current value if we switch to BCD counting */
|
||||
PitChannels[Channel].Bcd = IsBcd;
|
||||
if (IsBcd && PitChannels[Channel].CurrentValue > 9999)
|
||||
PitChannels[Channel].CurrentValue = 9999;
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
{
|
||||
PitChannels[Channel].Mode = Mode;
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
case 7:
|
||||
{
|
||||
/*
|
||||
* Modes 6 and 7 become PIT_MODE_RATE_GENERATOR
|
||||
* and PIT_MODE_SQUARE_WAVE respectively.
|
||||
*/
|
||||
PitChannels[Channel].Mode = Mode - 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PitInitCounter(&PitChannels[Channel]);
|
||||
}
|
||||
|
||||
static BYTE PitReadData(BYTE Channel)
|
||||
{
|
||||
LPBYTE ReadWriteMode = NULL;
|
||||
LPWORD CurrentValue = NULL;
|
||||
|
||||
/*
|
||||
* If the status was latched, the first read operation will return the
|
||||
* latched status, whichever value (count or status) was latched first.
|
||||
*/
|
||||
if (PitChannels[Channel].LatchStatusSet)
|
||||
{
|
||||
PitChannels[Channel].LatchStatusSet = FALSE;
|
||||
return PitChannels[Channel].StatusLatch;
|
||||
}
|
||||
|
||||
/* To be able to read the count asynchronously, latch it first if needed */
|
||||
if (PitChannels[Channel].ReadStatus == 0) PitLatchChannelCount(Channel);
|
||||
|
||||
/* The count is now latched */
|
||||
ASSERT(PitChannels[Channel].ReadStatus != 0);
|
||||
|
||||
ReadWriteMode = &PitChannels[Channel].ReadStatus ;
|
||||
CurrentValue = &PitChannels[Channel].OutputLatch;
|
||||
|
||||
if (*ReadWriteMode & 1)
|
||||
{
|
||||
/* Read LSB */
|
||||
*ReadWriteMode &= ~1;
|
||||
return LOBYTE(*CurrentValue);
|
||||
}
|
||||
|
||||
if (*ReadWriteMode & 2)
|
||||
{
|
||||
/* Read MSB */
|
||||
*ReadWriteMode &= ~2;
|
||||
return HIBYTE(*CurrentValue);
|
||||
}
|
||||
|
||||
/* Shouldn't get here */
|
||||
ASSERT(FALSE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID PitWriteData(BYTE Channel, BYTE Value)
|
||||
{
|
||||
LPBYTE ReadWriteMode = NULL;
|
||||
|
||||
if (PitChannels[Channel].WriteStatus == 0x00)
|
||||
{
|
||||
PitChannels[Channel].WriteStatus = PitChannels[Channel].ReadWriteMode;
|
||||
}
|
||||
|
||||
ASSERT(PitChannels[Channel].WriteStatus != 0);
|
||||
|
||||
ReadWriteMode = &PitChannels[Channel].WriteStatus;
|
||||
|
||||
if (*ReadWriteMode & 1)
|
||||
{
|
||||
/* Write LSB */
|
||||
*ReadWriteMode &= ~1;
|
||||
PitChannels[Channel].CountRegister &= 0xFF00;
|
||||
PitChannels[Channel].CountRegister |= Value;
|
||||
}
|
||||
else if (*ReadWriteMode & 2)
|
||||
{
|
||||
/* Write MSB */
|
||||
*ReadWriteMode &= ~2;
|
||||
PitChannels[Channel].CountRegister &= 0x00FF;
|
||||
PitChannels[Channel].CountRegister |= Value << 8;
|
||||
}
|
||||
|
||||
/* ReadWriteMode went to zero: we are going to load the new count */
|
||||
if (*ReadWriteMode == 0x00)
|
||||
{
|
||||
if (PitChannels[Channel].CountRegister == 0x0000)
|
||||
{
|
||||
/* Wrap around to the highest count */
|
||||
if (PitChannels[Channel].Bcd)
|
||||
PitChannels[Channel].CountRegister = 9999;
|
||||
else
|
||||
PitChannels[Channel].CountRegister = 0xFFFF; // 0x10000; // 65536
|
||||
}
|
||||
|
||||
/* Convert the current value from BCD if needed */
|
||||
PitChannels[Channel].CountRegister =
|
||||
WRITE_PIT_VALUE(PitChannels[Channel], PitChannels[Channel].CountRegister);
|
||||
PitChannels[Channel].ReloadValue = PitChannels[Channel].CountRegister;
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE WINAPI PitReadPort(ULONG Port)
|
||||
{
|
||||
switch (Port)
|
||||
{
|
||||
case PIT_DATA_PORT(0):
|
||||
case PIT_DATA_PORT(1):
|
||||
case PIT_DATA_PORT(2):
|
||||
{
|
||||
return PitReadData(Port - PIT_DATA_PORT(0));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID WINAPI PitWritePort(ULONG Port, BYTE Data)
|
||||
{
|
||||
switch (Port)
|
||||
{
|
||||
case PIT_COMMAND_PORT:
|
||||
{
|
||||
PitWriteCommand(Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PIT_DATA_PORT(0):
|
||||
case PIT_DATA_PORT(1):
|
||||
case PIT_DATA_PORT(2):
|
||||
{
|
||||
PitWriteData(Port - PIT_DATA_PORT(0), Data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
|
||||
{
|
||||
if (Count == 0) return;
|
||||
|
||||
switch (Channel->Mode)
|
||||
{
|
||||
case PIT_MODE_INT_ON_TERMINAL_COUNT:
|
||||
{
|
||||
/* Decrement the value */
|
||||
if (Count > Channel->CurrentValue)
|
||||
{
|
||||
/* The value does not reload in this case */
|
||||
Channel->CurrentValue = 0;
|
||||
}
|
||||
else Channel->CurrentValue -= Count;
|
||||
|
||||
/* Did it fall to the terminal count? */
|
||||
if (Channel->CurrentValue == 0 && !Channel->Out)
|
||||
{
|
||||
/* Yes, raise the output line */
|
||||
PitSetOut(Channel, TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PIT_MODE_RATE_GENERATOR:
|
||||
{
|
||||
BOOLEAN Reloaded = FALSE;
|
||||
|
||||
while (Count)
|
||||
{
|
||||
if ((Count > Channel->CurrentValue)
|
||||
&& (Channel->CurrentValue != 0))
|
||||
{
|
||||
/* Decrement the count */
|
||||
Count -= Channel->CurrentValue;
|
||||
|
||||
/* Reload the value */
|
||||
Channel->CurrentValue = Channel->ReloadValue;
|
||||
|
||||
/* Set the flag */
|
||||
Reloaded = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Decrement the value */
|
||||
Channel->CurrentValue -= Count;
|
||||
|
||||
/* Clear the count */
|
||||
Count = 0;
|
||||
|
||||
/* Did it fall to zero? */
|
||||
if (Channel->CurrentValue == 0)
|
||||
{
|
||||
Channel->CurrentValue = Channel->ReloadValue;
|
||||
Reloaded = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was a reload, raise the output line */
|
||||
if (Reloaded) PitSetOut(Channel, TRUE);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PIT_MODE_SQUARE_WAVE:
|
||||
{
|
||||
INT ReloadCount = 0;
|
||||
WORD ReloadValue = Channel->ReloadValue;
|
||||
|
||||
/* The reload value must be even */
|
||||
ReloadValue &= ~1;
|
||||
|
||||
while (Count)
|
||||
{
|
||||
if (((Count * 2) > Channel->CurrentValue)
|
||||
&& (Channel->CurrentValue != 0))
|
||||
{
|
||||
/* Decrement the count */
|
||||
Count -= Channel->CurrentValue / 2;
|
||||
|
||||
/* Reload the value */
|
||||
Channel->CurrentValue = ReloadValue;
|
||||
|
||||
/* Increment the reload count */
|
||||
ReloadCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Decrement the value */
|
||||
Channel->CurrentValue -= Count * 2;
|
||||
|
||||
/* Clear the count */
|
||||
Count = 0;
|
||||
|
||||
/* Did it fall to zero? */
|
||||
if (Channel->CurrentValue == 0)
|
||||
{
|
||||
/* Reload the value */
|
||||
Channel->CurrentValue = ReloadValue;
|
||||
|
||||
/* Increment the reload count */
|
||||
ReloadCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ReloadCount == 0) break;
|
||||
|
||||
/* Toggle the flip-flop if the number of reloads was odd */
|
||||
if (ReloadCount & 1)
|
||||
{
|
||||
Channel->FlipFlop = !Channel->FlipFlop;
|
||||
// PitSetOut(Channel, !Channel->Out);
|
||||
}
|
||||
|
||||
/* Was there any rising edge? */
|
||||
if ((Channel->FlipFlop && (ReloadCount == 1)) || (ReloadCount > 1))
|
||||
{
|
||||
/* Yes, raise the output line */
|
||||
PitSetOut(Channel, TRUE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PIT_MODE_SOFTWARE_STROBE:
|
||||
{
|
||||
// TODO: NOT IMPLEMENTED
|
||||
break;
|
||||
}
|
||||
|
||||
case PIT_MODE_HARDWARE_ONE_SHOT:
|
||||
case PIT_MODE_HARDWARE_STROBE:
|
||||
{
|
||||
/* These modes do not work on x86 PCs */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
|
||||
{
|
||||
if (Channel >= PIT_CHANNELS) return;
|
||||
|
||||
PitChannels[Channel].OutParam = Param;
|
||||
PitChannels[Channel].OutFunction = OutFunction;
|
||||
}
|
||||
|
||||
VOID PitSetGate(BYTE Channel, BOOLEAN State)
|
||||
{
|
||||
if (Channel >= PIT_CHANNELS) return;
|
||||
if (State == PitChannels[Channel].Gate) return;
|
||||
|
||||
/* UNIMPLEMENTED */
|
||||
PitChannels[Channel].Gate = State;
|
||||
}
|
||||
|
||||
VOID PitClock(DWORD Count)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (Count == 0) return;
|
||||
|
||||
for (i = 0; i < PIT_CHANNELS; i++)
|
||||
{
|
||||
// if (!PitChannels[i].Counting) continue;
|
||||
PitDecrementCount(&PitChannels[i], Count);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD PitGetResolution(VOID)
|
||||
{
|
||||
INT i;
|
||||
DWORD MinReloadValue = 65536;
|
||||
|
||||
for (i = 0; i < PIT_CHANNELS; i++)
|
||||
{
|
||||
DWORD ReloadValue = PitChannels[i].ReloadValue;
|
||||
|
||||
/* 0 means 65536 */
|
||||
if (ReloadValue == 0) ReloadValue = 65536;
|
||||
|
||||
if (ReloadValue < MinReloadValue) MinReloadValue = ReloadValue;
|
||||
}
|
||||
|
||||
/* Return the frequency resolution */
|
||||
return PIT_BASE_FREQUENCY / MinReloadValue;
|
||||
}
|
||||
|
||||
VOID PitInitialize(VOID)
|
||||
{
|
||||
/* Set up the timers to their default value */
|
||||
PitSetOutFunction(0, NULL, NULL);
|
||||
PitSetGate(0, TRUE);
|
||||
PitSetOutFunction(1, NULL, NULL);
|
||||
PitSetGate(1, TRUE);
|
||||
PitSetOutFunction(2, NULL, NULL);
|
||||
PitSetGate(2, FALSE);
|
||||
|
||||
/* Register the I/O Ports */
|
||||
RegisterIoPort(PIT_COMMAND_PORT, NULL , PitWritePort);
|
||||
RegisterIoPort(PIT_DATA_PORT(0), PitReadPort, PitWritePort);
|
||||
RegisterIoPort(PIT_DATA_PORT(1), PitReadPort, PitWritePort);
|
||||
RegisterIoPort(PIT_DATA_PORT(2), PitReadPort, PitWritePort);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: timer.h
|
||||
* PURPOSE: Programmable Interval Timer emulation -
|
||||
* i82C54/8254 compatible
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito ([email protected])
|
||||
*/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define PIT_CHANNELS 3
|
||||
#define PIT_BASE_FREQUENCY 1193182LL
|
||||
#define PIT_DATA_PORT(x) (0x40 + (x))
|
||||
#define PIT_COMMAND_PORT 0x43
|
||||
|
||||
#define WRITE_PIT_VALUE(PitChannel, Value) \
|
||||
(PitChannel).Bcd ? BCD_TO_BINARY(Value) : (Value)
|
||||
|
||||
#define READ_PIT_VALUE(PitChannel, Value) \
|
||||
(PitChannel).Bcd ? BINARY_TO_BCD(Value) : (Value)
|
||||
|
||||
typedef enum _PIT_MODE
|
||||
{
|
||||
PIT_MODE_INT_ON_TERMINAL_COUNT,
|
||||
PIT_MODE_HARDWARE_ONE_SHOT,
|
||||
PIT_MODE_RATE_GENERATOR,
|
||||
PIT_MODE_SQUARE_WAVE,
|
||||
PIT_MODE_SOFTWARE_STROBE,
|
||||
PIT_MODE_HARDWARE_STROBE
|
||||
} PIT_MODE, *PPIT_MODE;
|
||||
|
||||
typedef VOID (WINAPI *PIT_OUT_FUNCTION)(LPVOID Param, BOOLEAN State);
|
||||
|
||||
typedef struct _PIT_CHANNEL
|
||||
{
|
||||
/* PIT Status fields */
|
||||
PIT_MODE Mode;
|
||||
BOOLEAN Bcd;
|
||||
BYTE ReadWriteMode; // 0 --> Counter Latch ; 1 --> LSB R/W ; 2 --> MSB R/W ; 3 --> LSB then MSB R/W
|
||||
|
||||
/* For interleaved reading and writing in 2-byte RW mode */
|
||||
BYTE ReadStatus; // Same convention as ReadWriteMode
|
||||
BYTE WriteStatus; // Same convention as ReadWriteMode
|
||||
|
||||
/* For reading the PIT status byte */
|
||||
BOOLEAN LatchStatusSet;
|
||||
BYTE StatusLatch;
|
||||
|
||||
/* Counting */
|
||||
BOOLEAN Gate;
|
||||
|
||||
/**/WORD CountRegister;/**/ // Our ReloadValue ???
|
||||
WORD OutputLatch;
|
||||
/*******************************/
|
||||
|
||||
WORD ReloadValue; // Max value of the counter
|
||||
WORD CurrentValue; // Real value of the counter
|
||||
|
||||
/* PIT Output */
|
||||
BOOLEAN Out; // 0: Low ; 1: High
|
||||
/** HACK!! **/BOOLEAN FlipFlop;/** HACK!! **/
|
||||
LPVOID OutParam;
|
||||
PIT_OUT_FUNCTION OutFunction;
|
||||
|
||||
} PIT_CHANNEL, *PPIT_CHANNEL;
|
||||
|
||||
extern PPIT_CHANNEL PitChannel2; // Needed for PC Speaker
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction);
|
||||
VOID PitSetGate(BYTE Channel, BOOLEAN State);
|
||||
|
||||
VOID PitClock(DWORD Count);
|
||||
DWORD PitGetResolution(VOID);
|
||||
|
||||
VOID PitInitialize(VOID);
|
||||
|
||||
#endif // _TIMER_H_
|
||||
|
||||
/* EOF */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: vga.h
|
||||
* PURPOSE: VGA hardware emulation
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _VGA_H_
|
||||
#define _VGA_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "ntvdm.h"
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define VGA_NUM_BANKS 4
|
||||
#define VGA_BANK_SIZE 0x10000
|
||||
#define VGA_MAX_COLORS 256
|
||||
#define VGA_PALETTE_SIZE (VGA_MAX_COLORS * 3)
|
||||
#define VGA_BITMAP_INFO_SIZE (sizeof(BITMAPINFOHEADER) + 2 * (VGA_PALETTE_SIZE / 3))
|
||||
#define VGA_MINIMUM_WIDTH 400
|
||||
#define VGA_MINIMUM_HEIGHT 300
|
||||
#define VGA_DAC_TO_COLOR(x) (((x) << 2) | ((x) >> 4))
|
||||
#define VGA_COLOR_TO_DAC(x) ((x) >> 2)
|
||||
|
||||
|
||||
|
||||
/* Register I/O ports */
|
||||
|
||||
#define VGA_MISC_READ 0x3CC
|
||||
#define VGA_MISC_WRITE 0x3C2
|
||||
|
||||
#define VGA_INSTAT0_READ 0x3C2
|
||||
|
||||
#define VGA_INSTAT1_READ_MONO 0x3BA
|
||||
#define VGA_INSTAT1_READ_COLOR 0x3DA
|
||||
|
||||
#define VGA_FEATURE_READ 0x3CA
|
||||
#define VGA_FEATURE_WRITE_MONO 0x3BA
|
||||
#define VGA_FEATURE_WRITE_COLOR 0x3DA
|
||||
|
||||
#define VGA_AC_INDEX 0x3C0
|
||||
#define VGA_AC_WRITE 0x3C0
|
||||
#define VGA_AC_READ 0x3C1
|
||||
|
||||
#define VGA_SEQ_INDEX 0x3C4
|
||||
#define VGA_SEQ_DATA 0x3C5
|
||||
|
||||
#define VGA_DAC_MASK 0x3C6
|
||||
#define VGA_DAC_READ_INDEX 0x3C7
|
||||
#define VGA_DAC_WRITE_INDEX 0x3C8
|
||||
#define VGA_DAC_DATA 0x3C9
|
||||
|
||||
#define VGA_CRTC_INDEX_MONO 0x3B4
|
||||
#define VGA_CRTC_DATA_MONO 0x3B5
|
||||
#define VGA_CRTC_INDEX_COLOR 0x3D4
|
||||
#define VGA_CRTC_DATA_COLOR 0x3D5
|
||||
|
||||
#define VGA_GC_INDEX 0x3CE
|
||||
#define VGA_GC_DATA 0x3CF
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Miscellaneous and Status Registers
|
||||
//
|
||||
|
||||
/* Miscellaneous register bits */
|
||||
#define VGA_MISC_COLOR (1 << 0)
|
||||
#define VGA_MISC_RAM_ENABLED (1 << 1)
|
||||
// #define VGA_MISC_CSEL1 (1 << 2)
|
||||
// #define VGA_MISC_CSEL2 (1 << 3)
|
||||
#define VGA_MISC_OE_INVERT (1 << 5)
|
||||
#define VGA_MISC_HSYNCP (1 << 6)
|
||||
#define VGA_MISC_VSYNCP (1 << 7)
|
||||
|
||||
/* Status register flags */
|
||||
#define VGA_STAT_DD (1 << 0)
|
||||
#define VGA_STAT_VRETRACE (1 << 3)
|
||||
|
||||
|
||||
//
|
||||
// Sequencer Registers
|
||||
//
|
||||
|
||||
/* Sequencer reset register bits */
|
||||
#define VGA_SEQ_RESET_AR (1 << 0)
|
||||
#define VGA_SEQ_RESET_SR (1 << 1)
|
||||
|
||||
/* Sequencer clock register bits */
|
||||
#define VGA_SEQ_CLOCK_98DM (1 << 0)
|
||||
#define VGA_SEQ_CLOCK_SLR (1 << 2)
|
||||
#define VGA_SEQ_CLOCK_DCR (1 << 3)
|
||||
#define VGA_SEQ_CLOCK_S4 (1 << 4)
|
||||
#define VGA_SEQ_CLOCK_SD (1 << 5)
|
||||
|
||||
/* Sequencer memory register bits */
|
||||
#define VGA_SEQ_MEM_EXT (1 << 1)
|
||||
#define VGA_SEQ_MEM_OE (1 << 2)
|
||||
#define VGA_SEQ_MEM_C4 (1 << 3)
|
||||
|
||||
enum
|
||||
{
|
||||
VGA_SEQ_RESET_REG,
|
||||
VGA_SEQ_CLOCK_REG,
|
||||
VGA_SEQ_MASK_REG,
|
||||
VGA_SEQ_CHAR_REG,
|
||||
VGA_SEQ_MEM_REG,
|
||||
VGA_SEQ_MAX_REG
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CRT Controller Registers
|
||||
//
|
||||
|
||||
/* CRTC overflow register bits */
|
||||
#define VGA_CRTC_OVERFLOW_VT8 (1 << 0)
|
||||
#define VGA_CRTC_OVERFLOW_VDE8 (1 << 1)
|
||||
#define VGA_CRTC_OVERFLOW_VRS8 (1 << 2)
|
||||
#define VGA_CRTC_OVERFLOW_SVB8 (1 << 3)
|
||||
#define VGA_CRTC_OVERFLOW_LC8 (1 << 4)
|
||||
#define VGA_CRTC_OVERFLOW_VT9 (1 << 5)
|
||||
#define VGA_CRTC_OVERFLOW_VDE9 (1 << 6)
|
||||
#define VGA_CRTC_OVERFLOW_VRS9 (1 << 7)
|
||||
|
||||
/* CRTC underline register bits */
|
||||
#define VGA_CRTC_UNDERLINE_DWORD (1 << 6)
|
||||
|
||||
/* CRTC max scanline register bits */
|
||||
#define VGA_CRTC_MAXSCANLINE_DOUBLE (1 << 7)
|
||||
|
||||
/* CRTC mode control register bits */
|
||||
#define VGA_CRTC_MODE_CONTROL_WRAP (1 << 5)
|
||||
#define VGA_CRTC_MODE_CONTROL_BYTE (1 << 6)
|
||||
#define VGA_CRTC_MODE_CONTROL_SYNC (1 << 7)
|
||||
|
||||
enum
|
||||
{
|
||||
VGA_CRTC_HORZ_TOTAL_REG,
|
||||
VGA_CRTC_END_HORZ_DISP_REG,
|
||||
VGA_CRTC_START_HORZ_BLANKING_REG,
|
||||
VGA_CRTC_END_HORZ_BLANKING_REG,
|
||||
VGA_CRTC_START_HORZ_RETRACE_REG,
|
||||
VGA_CRTC_END_HORZ_RETRACE_REG,
|
||||
VGA_CRTC_VERT_TOTAL_REG,
|
||||
VGA_CRTC_OVERFLOW_REG,
|
||||
VGA_CRTC_PRESET_ROW_SCAN_REG,
|
||||
VGA_CRTC_MAX_SCAN_LINE_REG,
|
||||
VGA_CRTC_CURSOR_START_REG,
|
||||
VGA_CRTC_CURSOR_END_REG,
|
||||
VGA_CRTC_START_ADDR_HIGH_REG,
|
||||
VGA_CRTC_START_ADDR_LOW_REG,
|
||||
VGA_CRTC_CURSOR_LOC_HIGH_REG,
|
||||
VGA_CRTC_CURSOR_LOC_LOW_REG,
|
||||
VGA_CRTC_VERT_RETRACE_START_REG,
|
||||
VGA_CRTC_VERT_RETRACE_END_REG,
|
||||
VGA_CRTC_VERT_DISP_END_REG,
|
||||
VGA_CRTC_OFFSET_REG,
|
||||
VGA_CRTC_UNDERLINE_REG,
|
||||
VGA_CRTC_START_VERT_BLANKING_REG,
|
||||
VGA_CRTC_END_VERT_BLANKING,
|
||||
VGA_CRTC_MODE_CONTROL_REG,
|
||||
VGA_CRTC_LINE_COMPARE_REG,
|
||||
VGA_CRTC_MAX_REG
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Graphics Controller Registers
|
||||
//
|
||||
|
||||
/* Graphics controller mode register bits */
|
||||
#define VGA_GC_MODE_READ (1 << 3)
|
||||
#define VGA_GC_MODE_OE (1 << 4)
|
||||
#define VGA_GC_MODE_SHIFTREG (1 << 5)
|
||||
#define VGA_GC_MODE_SHIFT256 (1 << 6)
|
||||
|
||||
/* Graphics controller miscellaneous register bits */
|
||||
#define VGA_GC_MISC_NOALPHA (1 << 0)
|
||||
#define VGA_GC_MISC_OE (1 << 1)
|
||||
|
||||
enum
|
||||
{
|
||||
VGA_GC_RESET_REG,
|
||||
VGA_GC_ENABLE_RESET_REG,
|
||||
VGA_GC_COLOR_COMPARE_REG,
|
||||
VGA_GC_ROTATE_REG,
|
||||
VGA_GC_READ_MAP_SEL_REG,
|
||||
VGA_GC_MODE_REG,
|
||||
VGA_GC_MISC_REG,
|
||||
VGA_GC_COLOR_IGNORE_REG,
|
||||
VGA_GC_BITMASK_REG,
|
||||
VGA_GC_MAX_REG
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Attribute Controller Registers
|
||||
// They are a relinquish of the CGA/EGA era.
|
||||
//
|
||||
|
||||
/* AC mode control register bits */
|
||||
#define VGA_AC_CONTROL_ATGE (1 << 0)
|
||||
#define VGA_AC_CONTROL_MONO (1 << 1)
|
||||
#define VGA_AC_CONTROL_LGE (1 << 2)
|
||||
#define VGA_AC_CONTROL_BLINK (1 << 3)
|
||||
#define VGA_AC_CONTROL_PPM (1 << 5)
|
||||
#define VGA_AC_CONTROL_8BIT (1 << 6)
|
||||
#define VGA_AC_CONTROL_P54S (1 << 7)
|
||||
|
||||
enum
|
||||
{
|
||||
VGA_AC_PAL_0_REG,
|
||||
VGA_AC_PAL_1_REG,
|
||||
VGA_AC_PAL_2_REG,
|
||||
VGA_AC_PAL_3_REG,
|
||||
VGA_AC_PAL_4_REG,
|
||||
VGA_AC_PAL_5_REG,
|
||||
VGA_AC_PAL_6_REG,
|
||||
VGA_AC_PAL_7_REG,
|
||||
VGA_AC_PAL_8_REG,
|
||||
VGA_AC_PAL_9_REG,
|
||||
VGA_AC_PAL_A_REG,
|
||||
VGA_AC_PAL_B_REG,
|
||||
VGA_AC_PAL_C_REG,
|
||||
VGA_AC_PAL_D_REG,
|
||||
VGA_AC_PAL_E_REG,
|
||||
VGA_AC_PAL_F_REG,
|
||||
VGA_AC_CONTROL_REG,
|
||||
VGA_AC_OVERSCAN_REG,
|
||||
VGA_AC_COLOR_PLANE_REG,
|
||||
VGA_AC_HORZ_PANNING_REG,
|
||||
VGA_AC_COLOR_SEL_REG,
|
||||
VGA_AC_MAX_REG
|
||||
};
|
||||
|
||||
|
||||
typedef struct _VGA_REGISTERS
|
||||
{
|
||||
UCHAR Misc;
|
||||
UCHAR Sequencer[VGA_SEQ_MAX_REG];
|
||||
UCHAR CRT[VGA_CRTC_MAX_REG];
|
||||
UCHAR Graphics[VGA_GC_MAX_REG];
|
||||
UCHAR Attribute[VGA_AC_MAX_REG];
|
||||
} VGA_REGISTERS, *PVGA_REGISTERS;
|
||||
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOL VgaAttachToConsole(VOID);
|
||||
VOID VgaDetachFromConsole(BOOL ChangeMode);
|
||||
|
||||
DWORD VgaGetVideoBaseAddress(VOID);
|
||||
DWORD VgaGetVideoLimitAddress(VOID);
|
||||
COORD VgaGetDisplayResolution(VOID);
|
||||
VOID VgaRefreshDisplay(VOID);
|
||||
VOID VgaHorizontalRetrace(VOID);
|
||||
VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size);
|
||||
VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size);
|
||||
VOID VgaClearMemory(VOID);
|
||||
|
||||
BOOLEAN VgaInitialize(HANDLE TextHandle);
|
||||
VOID VgaCleanup(VOID);
|
||||
|
||||
#endif // _VGA_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: int32.c
|
||||
* PURPOSE: 32-bit Interrupt Handlers
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
// #define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "int32.h"
|
||||
|
||||
#include "bop.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
/*
|
||||
* This is the list of registered 32-bit Interrupt handlers.
|
||||
*/
|
||||
EMULATOR_INT32_PROC Int32Proc[EMULATOR_MAX_INT32_NUM] = { NULL };
|
||||
|
||||
/* BOP Identifiers */
|
||||
#define BOP_CONTROL 0xFF // Control BOP Handler
|
||||
#define BOP_CONTROL_DEFFUNC 0x00 // Default Control BOP Function
|
||||
|
||||
/* 32-bit Interrupt dispatcher function code for the Control BOP Handler */
|
||||
#define BOP_CONTROL_INT32 0xFF
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID WINAPI Int32Dispatch(LPWORD Stack)
|
||||
{
|
||||
/* Get the interrupt number */
|
||||
BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]);
|
||||
|
||||
/* Call the 32-bit Interrupt handler */
|
||||
if (Int32Proc[IntNum] != NULL)
|
||||
Int32Proc[IntNum](Stack);
|
||||
else
|
||||
DPRINT("Unhandled 32-bit interrupt: 0x%02X, AX = 0x%04X\n", IntNum, getAX());
|
||||
}
|
||||
|
||||
VOID WINAPI ControlBop(LPWORD Stack)
|
||||
{
|
||||
/* Get the Function Number and skip it */
|
||||
BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
|
||||
setIP(getIP() + 1);
|
||||
|
||||
if (FuncNum == BOP_CONTROL_INT32)
|
||||
Int32Dispatch(Stack);
|
||||
else
|
||||
DPRINT("Unassigned Control BOP Function: 0x%02X\n", FuncNum);
|
||||
}
|
||||
|
||||
VOID InitializeInt32(WORD BiosSegment)
|
||||
{
|
||||
LPDWORD IntVecTable = (LPDWORD)BaseAddress;
|
||||
LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0);
|
||||
USHORT i;
|
||||
WORD BopSeqOffset, Offset = 0;
|
||||
|
||||
/* Generate ISR stubs and fill the IVT */
|
||||
for (i = 0x00; i <= 0xFF; i++)
|
||||
{
|
||||
Offset = INT_HANDLER_OFFSET + (i << 4);
|
||||
IntVecTable[i] = MAKELONG(Offset, BiosSegment);
|
||||
|
||||
BiosCode[Offset++] = 0xFA; // cli
|
||||
|
||||
BiosCode[Offset++] = 0x6A; // push i
|
||||
BiosCode[Offset++] = (UCHAR)i;
|
||||
|
||||
/* The counter variable (initialized to 0) */
|
||||
BiosCode[Offset++] = 0x6A; // push 0
|
||||
BiosCode[Offset++] = 0x00;
|
||||
|
||||
/* Stack variables */
|
||||
BiosCode[Offset++] = 0x83; // sub sp, 4
|
||||
BiosCode[Offset++] = 0xEC;
|
||||
BiosCode[Offset++] = 0x04;
|
||||
|
||||
BopSeqOffset = COMMON_STUB_OFFSET - (Offset + 3);
|
||||
|
||||
BiosCode[Offset++] = 0xE9; // jmp near BOP_SEQ
|
||||
BiosCode[Offset++] = LOBYTE(BopSeqOffset);
|
||||
BiosCode[Offset++] = HIBYTE(BopSeqOffset);
|
||||
}
|
||||
|
||||
/* Write the common stub code */
|
||||
Offset = COMMON_STUB_OFFSET;
|
||||
|
||||
// BOP_SEQ:
|
||||
BiosCode[Offset++] = 0xF8; // clc
|
||||
|
||||
BiosCode[Offset++] = LOBYTE(EMULATOR_BOP); // BOP sequence
|
||||
BiosCode[Offset++] = HIBYTE(EMULATOR_BOP);
|
||||
BiosCode[Offset++] = BOP_CONTROL; // Control BOP
|
||||
BiosCode[Offset++] = BOP_CONTROL_INT32; // 32-bit Interrupt dispatcher
|
||||
|
||||
BiosCode[Offset++] = 0x73; // jnc EXIT (offset +4)
|
||||
BiosCode[Offset++] = 0x04;
|
||||
|
||||
BiosCode[Offset++] = 0xFB; // sti
|
||||
|
||||
// HACK: The following instruction should be HLT!
|
||||
BiosCode[Offset++] = 0x90; // nop
|
||||
|
||||
BiosCode[Offset++] = 0xEB; // jmp BOP_SEQ (offset -11)
|
||||
BiosCode[Offset++] = 0xF5;
|
||||
|
||||
// EXIT:
|
||||
BiosCode[Offset++] = 0x83; // add sp, 8
|
||||
BiosCode[Offset++] = 0xC4;
|
||||
BiosCode[Offset++] = 0x08;
|
||||
|
||||
BiosCode[Offset++] = 0xCF; // iret
|
||||
|
||||
/* Register the Control BOP */
|
||||
RegisterBop(BOP_CONTROL, ControlBop);
|
||||
}
|
||||
|
||||
VOID RegisterInt32(BYTE IntNumber, EMULATOR_INT32_PROC IntHandler)
|
||||
{
|
||||
Int32Proc[IntNumber] = IntHandler;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: int32.h
|
||||
* PURPOSE: 32-bit Interrupt Handlers
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
#ifndef _INT32_H_
|
||||
#define _INT32_H_
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* 32-bit Interrupt Identifiers */
|
||||
#define EMULATOR_MAX_INT32_NUM 0xFF + 1
|
||||
|
||||
#define INT_HANDLER_OFFSET 0x1000
|
||||
#define COMMON_STUB_OFFSET 0x2000
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
typedef VOID (WINAPI *EMULATOR_INT32_PROC)(LPWORD Stack);
|
||||
|
||||
VOID WINAPI Int32Dispatch(LPWORD Stack);
|
||||
VOID InitializeInt32(WORD BiosSegment);
|
||||
VOID RegisterInt32(BYTE IntNumber, EMULATOR_INT32_PROC IntHandler);
|
||||
|
||||
#endif // _INT32_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,605 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: io.c
|
||||
* PURPOSE: I/O Port Handlers
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
#include "io.h"
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
typedef struct _EMULATOR_IO_HANDLERS
|
||||
{
|
||||
EMULATOR_INB_PROC InB;
|
||||
EMULATOR_INW_PROC InW;
|
||||
EMULATOR_IND_PROC InD;
|
||||
|
||||
EMULATOR_INSB_PROC InsB;
|
||||
EMULATOR_INSW_PROC InsW;
|
||||
EMULATOR_INSD_PROC InsD;
|
||||
|
||||
EMULATOR_OUTB_PROC OutB;
|
||||
EMULATOR_OUTW_PROC OutW;
|
||||
EMULATOR_OUTD_PROC OutD;
|
||||
|
||||
EMULATOR_OUTSB_PROC OutsB;
|
||||
EMULATOR_OUTSW_PROC OutsW;
|
||||
EMULATOR_OUTSD_PROC OutsD;
|
||||
} EMULATOR_IO_HANDLERS, *PEMULATOR_IO_HANDLERS;
|
||||
|
||||
typedef struct _EMULATOR_IOPORT_HANDLERS
|
||||
{
|
||||
HANDLE hVdd; // == 0 if unused,
|
||||
// INVALID_HANDLE_VALUE if handled internally,
|
||||
// a valid VDD handle if handled externally.
|
||||
union
|
||||
{
|
||||
/* For Windows compatibility only, not used internally... */
|
||||
VDD_IO_HANDLERS VddIoHandlers;
|
||||
|
||||
/* ... we use these members internally */
|
||||
EMULATOR_IO_HANDLERS IoHandlers;
|
||||
};
|
||||
} EMULATOR_IOPORT_HANDLERS, *PEMULATOR_IOPORT_HANDLERS;
|
||||
|
||||
/*
|
||||
* This is the list of registered I/O Port handlers.
|
||||
*/
|
||||
EMULATOR_IOPORT_HANDLERS IoPortProc[EMULATOR_MAX_IOPORTS_NUM] = {{NULL}};
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
UCHAR
|
||||
IOReadB(ULONG Port)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.InB)
|
||||
{
|
||||
return IoPortProc[Port].IoHandlers.InB(Port);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.inb_handler)
|
||||
{
|
||||
UCHAR Data;
|
||||
ASSERT(Port <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.inb_handler((WORD)Port, &Data);
|
||||
return Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return an empty port byte value */
|
||||
DPRINT("Read from unknown port: 0x%X\n", Port);
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOReadStrB(ULONG Port,
|
||||
PUCHAR Buffer,
|
||||
ULONG Count)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.InsB)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.InsB(Port, Buffer, Count);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.insb_handler)
|
||||
{
|
||||
ASSERT(Port <= MAXWORD);
|
||||
ASSERT(Count <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.insb_handler((WORD)Port, Buffer, (WORD)Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Count--)
|
||||
*Buffer++ = IOReadB(Port);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOWriteB(ULONG Port,
|
||||
UCHAR Buffer)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.OutB)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.OutB(Port, Buffer);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.outb_handler)
|
||||
{
|
||||
ASSERT(Port <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.outb_handler((WORD)Port, Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do nothing */
|
||||
DPRINT("Write to unknown port: 0x%X\n", Port);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOWriteStrB(ULONG Port,
|
||||
PUCHAR Buffer,
|
||||
ULONG Count)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.OutsB)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.OutsB(Port, Buffer, Count);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.outsb_handler)
|
||||
{
|
||||
ASSERT(Port <= MAXWORD);
|
||||
ASSERT(Count <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.outsb_handler((WORD)Port, Buffer, (WORD)Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Count--) IOWriteB(Port, *Buffer++);
|
||||
}
|
||||
}
|
||||
|
||||
USHORT
|
||||
IOReadW(ULONG Port)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.InW)
|
||||
{
|
||||
return IoPortProc[Port].IoHandlers.InW(Port);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.inw_handler)
|
||||
{
|
||||
USHORT Data;
|
||||
ASSERT(Port <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.inw_handler((WORD)Port, &Data);
|
||||
return Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
UCHAR Low, High;
|
||||
|
||||
// FIXME: Is it ok on Little endian and Big endian ??
|
||||
Low = IOReadB(Port);
|
||||
High = IOReadB(Port + sizeof(UCHAR));
|
||||
return MAKEWORD(Low, High);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOReadStrW(ULONG Port,
|
||||
PUSHORT Buffer,
|
||||
ULONG Count)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.InsW)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.InsW(Port, Buffer, Count);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.insw_handler)
|
||||
{
|
||||
ASSERT(Port <= MAXWORD);
|
||||
ASSERT(Count <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.insw_handler((WORD)Port, Buffer, (WORD)Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Count--)
|
||||
*Buffer++ = IOReadW(Port);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOWriteW(ULONG Port,
|
||||
USHORT Buffer)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.OutW)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.OutW(Port, Buffer);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.outw_handler)
|
||||
{
|
||||
ASSERT(Port <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.outw_handler((WORD)Port, Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Is it ok on Little endian and Big endian ??
|
||||
IOWriteB(Port, LOBYTE(Buffer));
|
||||
IOWriteB(Port + sizeof(UCHAR), HIBYTE(Buffer));
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOWriteStrW(ULONG Port,
|
||||
PUSHORT Buffer,
|
||||
ULONG Count)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.OutsW)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.OutsW(Port, Buffer, Count);
|
||||
}
|
||||
else if (IoPortProc[Port].hVdd > 0 &&
|
||||
IoPortProc[Port].VddIoHandlers.outsw_handler)
|
||||
{
|
||||
ASSERT(Port <= MAXWORD);
|
||||
ASSERT(Count <= MAXWORD);
|
||||
IoPortProc[Port].VddIoHandlers.outsw_handler((WORD)Port, Buffer, (WORD)Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Count--) IOWriteW(Port, *Buffer++);
|
||||
}
|
||||
}
|
||||
|
||||
ULONG
|
||||
IOReadD(ULONG Port)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.InD)
|
||||
{
|
||||
return IoPortProc[Port].IoHandlers.InD(Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
USHORT Low, High;
|
||||
|
||||
// FIXME: Is it ok on Little endian and Big endian ??
|
||||
Low = IOReadW(Port);
|
||||
High = IOReadW(Port + sizeof(USHORT));
|
||||
return MAKELONG(Low, High);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOReadStrD(ULONG Port,
|
||||
PULONG Buffer,
|
||||
ULONG Count)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.InsD)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.InsD(Port, Buffer, Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Count--)
|
||||
*Buffer++ = IOReadD(Port);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOWriteD(ULONG Port,
|
||||
ULONG Buffer)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.OutD)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.OutD(Port, Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Is it ok on Little endian and Big endian ??
|
||||
IOWriteW(Port, LOWORD(Buffer));
|
||||
IOWriteW(Port + sizeof(USHORT), HIWORD(Buffer));
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IOWriteStrD(ULONG Port,
|
||||
PULONG Buffer,
|
||||
ULONG Count)
|
||||
{
|
||||
if (IoPortProc[Port].hVdd == INVALID_HANDLE_VALUE &&
|
||||
IoPortProc[Port].IoHandlers.OutsD)
|
||||
{
|
||||
IoPortProc[Port].IoHandlers.OutsD(Port, Buffer, Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Count--) IOWriteD(Port, *Buffer++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID RegisterIoPort(ULONG Port,
|
||||
EMULATOR_INB_PROC InHandler,
|
||||
EMULATOR_OUTB_PROC OutHandler)
|
||||
{
|
||||
if (IoPortProc[Port].IoHandlers.InB == NULL)
|
||||
IoPortProc[Port].IoHandlers.InB = InHandler;
|
||||
else
|
||||
DPRINT1("IoPortProc[0x%X].IoHandlers.InB already registered\n", Port);
|
||||
|
||||
if (IoPortProc[Port].IoHandlers.OutB == NULL)
|
||||
IoPortProc[Port].IoHandlers.OutB = OutHandler;
|
||||
else
|
||||
DPRINT1("IoPortProc[0x%X].IoHandlers.OutB already registered\n", Port);
|
||||
|
||||
/* We hold the I/O port internally */
|
||||
IoPortProc[Port].hVdd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
VOID UnregisterIoPort(ULONG Port)
|
||||
{
|
||||
/*
|
||||
* Put automagically all the fields to zero:
|
||||
* the hVdd gets unregistered as well as all the handlers.
|
||||
*/
|
||||
// IoPortProc[Port] = {NULL};
|
||||
ZeroMemory(&IoPortProc[Port], sizeof(IoPortProc[Port]));
|
||||
}
|
||||
|
||||
VOID WINAPI
|
||||
EmulatorReadIo(PFAST486_STATE State,
|
||||
ULONG Port,
|
||||
PVOID Buffer,
|
||||
ULONG DataCount,
|
||||
UCHAR DataSize)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
|
||||
if (DataSize == 0 || DataCount == 0) return;
|
||||
|
||||
if (DataSize == sizeof(UCHAR))
|
||||
{
|
||||
if (DataCount == 1)
|
||||
*(PUCHAR)Buffer = IOReadB(Port);
|
||||
else
|
||||
IOReadStrB(Port, Buffer, DataCount);
|
||||
}
|
||||
else if (DataSize == sizeof(USHORT))
|
||||
{
|
||||
if (DataCount == 1)
|
||||
*(PUSHORT)Buffer = IOReadW(Port);
|
||||
else
|
||||
IOReadStrW(Port, Buffer, DataCount);
|
||||
}
|
||||
else if (DataSize == sizeof(ULONG))
|
||||
{
|
||||
if (DataCount == 1)
|
||||
*(PULONG)Buffer = IOReadD(Port);
|
||||
else
|
||||
IOReadStrD(Port, Buffer, DataCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
PBYTE Address = (PBYTE)Buffer;
|
||||
|
||||
while (DataCount--)
|
||||
{
|
||||
ULONG CurrentPort = Port;
|
||||
ULONG Count;
|
||||
UCHAR NewDataSize = DataSize;
|
||||
|
||||
/* Read dword */
|
||||
Count = NewDataSize / sizeof(ULONG);
|
||||
NewDataSize = NewDataSize % sizeof(ULONG);
|
||||
while (Count--)
|
||||
{
|
||||
*(PULONG)Address = IOReadD(CurrentPort);
|
||||
CurrentPort += sizeof(ULONG);
|
||||
Address += sizeof(ULONG);
|
||||
}
|
||||
|
||||
/* Read word */
|
||||
Count = NewDataSize / sizeof(USHORT);
|
||||
NewDataSize = NewDataSize % sizeof(USHORT);
|
||||
while (Count--)
|
||||
{
|
||||
*(PUSHORT)Address = IOReadW(CurrentPort);
|
||||
CurrentPort += sizeof(USHORT);
|
||||
Address += sizeof(USHORT);
|
||||
}
|
||||
|
||||
/* Read byte */
|
||||
Count = NewDataSize / sizeof(UCHAR);
|
||||
NewDataSize = NewDataSize % sizeof(UCHAR);
|
||||
while (Count--)
|
||||
{
|
||||
*(PUCHAR)Address = IOReadB(CurrentPort);
|
||||
CurrentPort += sizeof(UCHAR);
|
||||
Address += sizeof(UCHAR);
|
||||
}
|
||||
|
||||
ASSERT(Count == 0);
|
||||
ASSERT(NewDataSize == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID WINAPI
|
||||
EmulatorWriteIo(PFAST486_STATE State,
|
||||
ULONG Port,
|
||||
PVOID Buffer,
|
||||
ULONG DataCount,
|
||||
UCHAR DataSize)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(State);
|
||||
|
||||
if (DataSize == 0 || DataCount == 0) return;
|
||||
|
||||
if (DataSize == sizeof(UCHAR))
|
||||
{
|
||||
if (DataCount == 1)
|
||||
IOWriteB(Port, *(PUCHAR)Buffer);
|
||||
else
|
||||
IOWriteStrB(Port, Buffer, DataCount);
|
||||
}
|
||||
else if (DataSize == sizeof(USHORT))
|
||||
{
|
||||
if (DataCount == 1)
|
||||
IOWriteW(Port, *(PUSHORT)Buffer);
|
||||
else
|
||||
IOWriteStrW(Port, Buffer, DataCount);
|
||||
}
|
||||
else if (DataSize == sizeof(ULONG))
|
||||
{
|
||||
if (DataCount == 1)
|
||||
IOWriteD(Port, *(PULONG)Buffer);
|
||||
else
|
||||
IOWriteStrD(Port, Buffer, DataCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
PBYTE Address = (PBYTE)Buffer;
|
||||
|
||||
while (DataCount--)
|
||||
{
|
||||
ULONG CurrentPort = Port;
|
||||
ULONG Count;
|
||||
UCHAR NewDataSize = DataSize;
|
||||
|
||||
/* Write dword */
|
||||
Count = NewDataSize / sizeof(ULONG);
|
||||
NewDataSize = NewDataSize % sizeof(ULONG);
|
||||
while (Count--)
|
||||
{
|
||||
IOWriteD(CurrentPort, *(PULONG)Address);
|
||||
CurrentPort += sizeof(ULONG);
|
||||
Address += sizeof(ULONG);
|
||||
}
|
||||
|
||||
/* Write word */
|
||||
Count = NewDataSize / sizeof(USHORT);
|
||||
NewDataSize = NewDataSize % sizeof(USHORT);
|
||||
while (Count--)
|
||||
{
|
||||
IOWriteW(CurrentPort, *(PUSHORT)Address);
|
||||
CurrentPort += sizeof(USHORT);
|
||||
Address += sizeof(USHORT);
|
||||
}
|
||||
|
||||
/* Write byte */
|
||||
Count = NewDataSize / sizeof(UCHAR);
|
||||
NewDataSize = NewDataSize % sizeof(UCHAR);
|
||||
while (Count--)
|
||||
{
|
||||
IOWriteB(CurrentPort, *(PUCHAR)Address);
|
||||
CurrentPort += sizeof(UCHAR);
|
||||
Address += sizeof(UCHAR);
|
||||
}
|
||||
|
||||
ASSERT(Count == 0);
|
||||
ASSERT(NewDataSize == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
VDDInstallIOHook(HANDLE hVdd,
|
||||
WORD cPortRange,
|
||||
PVDD_IO_PORTRANGE pPortRange,
|
||||
PVDD_IO_HANDLERS IOhandler)
|
||||
{
|
||||
/* Check possible validity of the VDD handle */
|
||||
if (hVdd == 0 || hVdd == INVALID_HANDLE_VALUE) return FALSE;
|
||||
|
||||
/* Loop for each range of I/O ports */
|
||||
while (cPortRange--)
|
||||
{
|
||||
WORD i;
|
||||
|
||||
/* Register the range of I/O ports */
|
||||
for (i = pPortRange->First; i <= pPortRange->Last; ++i)
|
||||
{
|
||||
/*
|
||||
* Don't do anything if the I/O port is already
|
||||
* handled internally or externally.
|
||||
*/
|
||||
if (IoPortProc[i].hVdd != 0)
|
||||
{
|
||||
DPRINT1("IoPortProc[0x%X] already registered\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Register wrt. the VDD */
|
||||
IoPortProc[i].hVdd = hVdd;
|
||||
|
||||
/* Disable the internal handlers */
|
||||
IoPortProc[i].IoHandlers.InB = NULL;
|
||||
IoPortProc[i].IoHandlers.InW = NULL;
|
||||
IoPortProc[i].IoHandlers.InD = NULL;
|
||||
|
||||
IoPortProc[i].IoHandlers.InsB = NULL;
|
||||
IoPortProc[i].IoHandlers.InsW = NULL;
|
||||
IoPortProc[i].IoHandlers.InsD = NULL;
|
||||
|
||||
IoPortProc[i].IoHandlers.OutB = NULL;
|
||||
IoPortProc[i].IoHandlers.OutW = NULL;
|
||||
IoPortProc[i].IoHandlers.OutD = NULL;
|
||||
|
||||
IoPortProc[i].IoHandlers.OutsB = NULL;
|
||||
IoPortProc[i].IoHandlers.OutsW = NULL;
|
||||
IoPortProc[i].IoHandlers.OutsD = NULL;
|
||||
|
||||
/* Save our handlers */
|
||||
IoPortProc[i].VddIoHandlers = *IOhandler;
|
||||
}
|
||||
|
||||
/* Go to the next range */
|
||||
++pPortRange;
|
||||
++IOhandler;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
VDDDeInstallIOHook(HANDLE hVdd,
|
||||
WORD cPortRange,
|
||||
PVDD_IO_PORTRANGE pPortRange)
|
||||
{
|
||||
/* Check possible validity of the VDD handle */
|
||||
if (hVdd == 0 || hVdd == INVALID_HANDLE_VALUE) return;
|
||||
|
||||
/* Loop for each range of I/O ports */
|
||||
while (cPortRange--)
|
||||
{
|
||||
WORD i;
|
||||
|
||||
/* Unregister the range of I/O ports */
|
||||
for (i = pPortRange->First; i <= pPortRange->Last; ++i)
|
||||
{
|
||||
/*
|
||||
* Don't do anything if we don't own the I/O port.
|
||||
*/
|
||||
if (IoPortProc[i].hVdd != hVdd)
|
||||
{
|
||||
DPRINT1("IoPortProc[0x%X] owned by somebody else\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put automagically all the fields to zero:
|
||||
* the hVdd gets unregistered as well as all the handlers.
|
||||
*/
|
||||
// IoPortProc[i] = {NULL};
|
||||
ZeroMemory(&IoPortProc[i], sizeof(IoPortProc[i]));
|
||||
}
|
||||
|
||||
/* Go to the next range */
|
||||
++pPortRange;
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: io.c
|
||||
* PURPOSE: I/O Port Handlers
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
#ifndef _IO_H_
|
||||
#define _IO_H_
|
||||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define EMULATOR_MAX_IOPORTS_NUM 0x10000
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
typedef UCHAR (WINAPI *EMULATOR_INB_PROC)(ULONG Port);
|
||||
typedef USHORT (WINAPI *EMULATOR_INW_PROC)(ULONG Port);
|
||||
typedef ULONG (WINAPI *EMULATOR_IND_PROC)(ULONG Port);
|
||||
|
||||
typedef VOID (WINAPI *EMULATOR_INSB_PROC)(ULONG Port, PUCHAR Buffer, ULONG Count);
|
||||
typedef VOID (WINAPI *EMULATOR_INSW_PROC)(ULONG Port, PUSHORT Buffer, ULONG Count);
|
||||
typedef VOID (WINAPI *EMULATOR_INSD_PROC)(ULONG Port, PULONG Buffer, ULONG Count);
|
||||
|
||||
typedef VOID (WINAPI *EMULATOR_OUTB_PROC)(ULONG Port, UCHAR Data);
|
||||
typedef VOID (WINAPI *EMULATOR_OUTW_PROC)(ULONG Port, USHORT Data);
|
||||
typedef VOID (WINAPI *EMULATOR_OUTD_PROC)(ULONG Port, ULONG Data);
|
||||
|
||||
typedef VOID (WINAPI *EMULATOR_OUTSB_PROC)(ULONG Port, PUCHAR Buffer, ULONG Count);
|
||||
typedef VOID (WINAPI *EMULATOR_OUTSW_PROC)(ULONG Port, PUSHORT Buffer, ULONG Count);
|
||||
typedef VOID (WINAPI *EMULATOR_OUTSD_PROC)(ULONG Port, PULONG Buffer, ULONG Count);
|
||||
|
||||
|
||||
UCHAR
|
||||
IOReadB(ULONG Port);
|
||||
VOID
|
||||
IOReadStrB(ULONG Port,
|
||||
PUCHAR Buffer,
|
||||
ULONG Count);
|
||||
|
||||
VOID
|
||||
IOWriteB(ULONG Port,
|
||||
UCHAR Buffer);
|
||||
VOID
|
||||
IOWriteStrB(ULONG Port,
|
||||
PUCHAR Buffer,
|
||||
ULONG Count);
|
||||
|
||||
USHORT
|
||||
IOReadW(ULONG Port);
|
||||
VOID
|
||||
IOReadStrW(ULONG Port,
|
||||
PUSHORT Buffer,
|
||||
ULONG Count);
|
||||
|
||||
VOID
|
||||
IOWriteW(ULONG Port,
|
||||
USHORT Buffer);
|
||||
VOID
|
||||
IOWriteStrW(ULONG Port,
|
||||
PUSHORT Buffer,
|
||||
ULONG Count);
|
||||
|
||||
ULONG
|
||||
IOReadD(ULONG Port);
|
||||
VOID
|
||||
IOReadStrD(ULONG Port,
|
||||
PULONG Buffer,
|
||||
ULONG Count);
|
||||
|
||||
VOID
|
||||
IOWriteD(ULONG Port,
|
||||
ULONG Buffer);
|
||||
VOID
|
||||
IOWriteStrD(ULONG Port,
|
||||
PULONG Buffer,
|
||||
ULONG Count);
|
||||
|
||||
|
||||
VOID RegisterIoPort(ULONG Port,
|
||||
EMULATOR_INB_PROC InHandler,
|
||||
EMULATOR_OUTB_PROC OutHandler);
|
||||
|
||||
VOID UnregisterIoPort(ULONG Port);
|
||||
|
||||
VOID WINAPI EmulatorReadIo
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Port,
|
||||
PVOID Buffer,
|
||||
ULONG DataCount,
|
||||
UCHAR DataSize
|
||||
);
|
||||
|
||||
VOID WINAPI EmulatorWriteIo
|
||||
(
|
||||
PFAST486_STATE State,
|
||||
ULONG Port,
|
||||
PVOID Buffer,
|
||||
ULONG DataCount,
|
||||
UCHAR DataSize
|
||||
);
|
||||
|
||||
#endif // _IO_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Поддръжка на РеактОС за привидна ДОС машина.\n"
|
||||
STRING_PromptMsg "Напишете r<cr> за пускане, s<cr> за спиране или q<cr> за изход."
|
||||
END
|
||||
@@ -1,12 +1,19 @@
|
||||
/* FILE: subsystems/ntvdm/lang/cs-CZ.rc
|
||||
/*
|
||||
* FILE: subsystems/ntvdm/lang/cs-CZ.rc
|
||||
* TRANSLATOR: Radek Liska aka Black_Fox (radekliska at gmail dot com)
|
||||
* UPDATED: 2008-06-24
|
||||
* UPDATED: 2014-02-01
|
||||
*/
|
||||
|
||||
|
||||
LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS podpora virtuálního DOS stroje.\n"
|
||||
STRING_PromptMsg "Napište r<cr> pro spuštìní, s<cr> pro vypnutí nebo q<cr> pro ukonèení."
|
||||
IDS_HIDE_MOUSE, "&Skrýt ukazatel myši"
|
||||
IDS_SHOW_MOUSE, "&Zobrazit ukazatel myši"
|
||||
IDS_VDM_MENU , "ReactOS &VDM"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_VDM_QUIT, "&Ukončit ReactOS VDM"
|
||||
END
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
* German translate
|
||||
* By Rouven Wessling 2005 [email protected]
|
||||
* 2008 [email protected]
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS virtuelle DOS-Unterstützung.\n"
|
||||
STRING_PromptMsg "Drücken Sie r<cr> zum Starten, s<cr> zum Herunterfahren oder q<cr> zum Beenden."
|
||||
IDS_HIDE_MOUSE, "Mauszeiger &verstecken"
|
||||
IDS_SHOW_MOUSE, "Mauszeiger &anzeigen"
|
||||
IDS_VDM_MENU , "&ReactOS VDM"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_VDM_QUIT, "ReactOS VDM b&eenden"
|
||||
END
|
||||
|
||||
@@ -2,6 +2,12 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS Virtual DOS Machine support.\n"
|
||||
STRING_PromptMsg "Type r<cr> to run, s<cr> to shutdown or q<cr> to quit now."
|
||||
IDS_HIDE_MOUSE, "&Hide Mouse Pointer"
|
||||
IDS_SHOW_MOUSE, "&Display Mouse Pointer"
|
||||
IDS_VDM_MENU , "ReactOS &VDM"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_VDM_QUIT, "&Quit the ReactOS VDM"
|
||||
END
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
/* Spanish translation by Samuel Serapion */
|
||||
|
||||
LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Maquina virtual de DOS en ReactOS.\n"
|
||||
STRING_PromptMsg "Escriba r<cr> para correr, s<cr> para desactivar or q<cr> para salir ahora."
|
||||
IDS_HIDE_MOUSE, "&Ocultar puntero del ratón"
|
||||
IDS_SHOW_MOUSE, "&Mostrar puntero del ratón"
|
||||
IDS_VDM_MENU , "ReactOS &VDM"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_VDM_QUIT, "&Salir de ReactOS VDM"
|
||||
END
|
||||
|
||||
@@ -2,6 +2,12 @@ LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Aide de la Machine DOS Virtuel de ReactOS.\n"
|
||||
STRING_PromptMsg "Taper r<cr> pour démarrer, s<cr> pour éteindre ou q<cr> pour quitter maintenant."
|
||||
IDS_HIDE_MOUSE, "Mas&quer le pointeur de la souris"
|
||||
IDS_SHOW_MOUSE, "&Afficher le pointeur de la souris"
|
||||
IDS_VDM_MENU , "ReactOS &VDM"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_VDM_QUIT, "&Quitter la ReactOS VDM"
|
||||
END
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/* Hungarian translation by Robert Horvath 2005 - talley at cubeclub.hu */
|
||||
|
||||
LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS Virtuális DOS Gép támogatás.\n"
|
||||
STRING_PromptMsg "Futtatáshoz nyomd meg a r<cr>, leállításhoz a s<cr> vagy kilépéshez a q<cr> gombot."
|
||||
END
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_INDONESIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Dukungan ReactOS Virtual DOS Machine.\n"
|
||||
STRING_PromptMsg "Ketik r<cr> untuk menjalankan, s<cr> untuk mematikan atau q<cr> untuk keluar sekarang."
|
||||
END
|
||||
@@ -1,15 +1,13 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: subsystems/ntvdm/it-IT.rc
|
||||
* PURPOSE: Italian Translation of subsystems/ntvdm/en-US.rc
|
||||
* TRANSLATOR: Daniele Forsi (dforsi at gmail.com)
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Supporto di ReactOS per la macchina virtuale DOS.\n"
|
||||
STRING_PromptMsg "Digitare r<invio> per avviare, s<invio> per arrestare o q<invio> per abbandonare ora."
|
||||
IDS_HIDE_MOUSE, "&Nascondi il mouse"
|
||||
IDS_SHOW_MOUSE, "&Mostra il mouse"
|
||||
IDS_VDM_MENU , "ReactOS &VDM"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_VDM_QUIT, "&Esci da ReactOS VDM"
|
||||
END
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS Virtual DOS Machine support.\n"
|
||||
STRING_PromptMsg "起動するには r<cr> を、シャットダウンするには s<cr> を、今すぐ終了させるには q<cr> を入力してください。"
|
||||
END
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS Vituell DOS Maskin støtte.\n"
|
||||
STRING_PromptMsg "Skriv r<cr> for å kjøre, s<cr> å avslutte eller q<cr> for å slutte nå."
|
||||
END
|
||||
@@ -1,14 +1,15 @@
|
||||
/*
|
||||
* Translated by xrogers
|
||||
* [email protected]
|
||||
* https://sourceforge.net/projects/reactospl
|
||||
* UTF-8 conversion by Caemyr (May, 2011)
|
||||
*/
|
||||
|
||||
// Created by wojo664 - Saved in UTF-8 encoding
|
||||
|
||||
LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Wirtualna maszyna DOS dla ReactOS.\n"
|
||||
STRING_PromptMsg "Wciśnij r<cr> aby uruchomić, s<cr> aby wyłączyć lub q<cr>, aby zakończyć."
|
||||
IDS_HIDE_MOUSE, "&Ukryj Wskaźnik Myszki"
|
||||
IDS_SHOW_MOUSE, "&Pokaż Wskaźnik Myszki"
|
||||
IDS_VDM_MENU , "ReactOS &VDM"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_VDM_QUIT, "&Wyjdź z ReactOS VDM"
|
||||
END
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS subsistema para suporte DOS de 16 bits.\n"
|
||||
STRING_PromptMsg "Digite r<cr> para executar, s<cr> para desligar ou q<cr> para sair."
|
||||
END
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* FILE: subsystems/ntvdm/lang/ro-RO.rc
|
||||
* ReactOS Project (http://www.reactos.org)
|
||||
* TRANSLATOR: Fulea Ștefan (PM on ReactOS Forum at fulea.stefan)
|
||||
* CHANGE LOG: 2011-10-16 initial translation
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Asistență pentru mașina virtuală DOS.\n"
|
||||
STRING_PromptMsg "Tastați r<cr> pentru a executa, s<cr> pentru a închide sau q<cr> pentru a ieși imediat."
|
||||
END
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Виртуальная машина поддержки DOS для ReactOS.\n"
|
||||
STRING_PromptMsg "Введите r<cr> для запуска, s<cr> для выключения или q<cr> выхода."
|
||||
END
|
||||
@@ -1,11 +0,0 @@
|
||||
/* TRANSLATOR: Mário Kaèmár /Mario Kacmar/ aka Kario ([email protected])
|
||||
* DATE OF TR: 12-02-2008
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Podpora virtuálneho DOSového stroja v systéme ReactOS.\n"
|
||||
STRING_PromptMsg "Napíšte r<cr> pre spustenie, s<cr> pre vypnutie alebo q<cr> pre okamžité skonèenie."
|
||||
END
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_THAI, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "รองรับการทำงานระบบดอสเสมือนของ ReactOS\n"
|
||||
STRING_PromptMsg "แบบ r<cr> เพื่อทำงาน, s<cr> เพื่อปิดระบบหรือ q<cr> เพื่อออกทันที"
|
||||
END
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* PROJECT: Virtual DOS Machine
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: subsystems/ntvdm/Uk.rc
|
||||
* PURPOSE: Ukraianian Language File for Virtual DOS Machine
|
||||
* TRANSLATOR: Artem Reznikov
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "Підтримка віртуальної машини DOS у ReactOS.\n"
|
||||
STRING_PromptMsg "Введіть r<cr> для запуску, s<cr> для закриття або q<cr>, щоб вийти зараз."
|
||||
END
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS 虚拟 DOS 机支持。\n"
|
||||
STRING_PromptMsg "输入 r<cr> 以便运行,s<cr> 以便关闭或者 q<cr> 以便立即退出。"
|
||||
END
|
||||
@@ -1,7 +0,0 @@
|
||||
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
STRING_WelcomeMsg "ReactOS 虛擬 DOS 機支援。\n"
|
||||
STRING_PromptMsg "鍵入 r<cr> 以便運行, s<cr> 以便關閉或者 q<cr> 以便立即退出。"
|
||||
END
|
||||
+535
-339
@@ -1,375 +1,571 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: subsys/ntvdm/ntvdm->c
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: ntvdm.c
|
||||
* PURPOSE: Virtual DOS Machine
|
||||
* PROGRAMMER: Robert Dickenson (robd@mok.lvcm.com)
|
||||
* UPDATE HISTORY:
|
||||
* Created 23/10/2002
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <stdarg.h>
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <wincon.h>
|
||||
#include <winuser.h>
|
||||
#include <stdio.h>
|
||||
#define NDEBUG
|
||||
|
||||
#include "ntvdm.h"
|
||||
#include "emulator.h"
|
||||
|
||||
#include "clock.h"
|
||||
#include "hardware/ps2.h"
|
||||
#include "hardware/vga.h"
|
||||
#include "bios/bios.h"
|
||||
#include "dos/dem.h"
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
/*
|
||||
* Activate this line if you want to run NTVDM in standalone mode with:
|
||||
* ntvdm.exe <program>
|
||||
*/
|
||||
// #define STANDALONE
|
||||
|
||||
/* GLOBALS ******************************************************************/
|
||||
/* VARIABLES ******************************************************************/
|
||||
|
||||
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
|
||||
static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
|
||||
static DWORD OrgConsoleInputMode, OrgConsoleOutputMode;
|
||||
static BOOLEAN AcceptCommands = TRUE;
|
||||
static HANDLE CommandThread = NULL;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
static HMENU hConsoleMenu = NULL;
|
||||
static INT VdmMenuPos = -1;
|
||||
static BOOLEAN ShowPointer = FALSE;
|
||||
|
||||
void PrintString(char* fmt,...)
|
||||
{
|
||||
char buffer[512];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
OutputDebugStringA(buffer);
|
||||
}
|
||||
ULONG SessionId = 0;
|
||||
HANDLE VdmTaskEvent = NULL;
|
||||
|
||||
/*
|
||||
GetVersion
|
||||
GetVolumeInformationW
|
||||
GetWindowsDirectoryA
|
||||
GlobalMemoryStatus
|
||||
HeapAlloc
|
||||
HeapCreate
|
||||
HeapDestroy
|
||||
HeapFree
|
||||
HeapReAlloc
|
||||
|
||||
GetNextVDMCommand
|
||||
ExitVDM
|
||||
RegisterConsoleVDM
|
||||
SetVDMCurrentDirectories
|
||||
VDMConsoleOperation
|
||||
WriteConsoleInputVDMW
|
||||
|
||||
NtSetLdtEntries
|
||||
NtTerminateProcess
|
||||
|
||||
NtMapViewOfSection
|
||||
NtUnmapViewOfSection
|
||||
|
||||
NtVdmControl
|
||||
* Those menu helpers were taken from the GUI frontend in winsrv.dll
|
||||
*/
|
||||
typedef struct tag_VDM_CONFIG {
|
||||
int dos_options;
|
||||
int files;
|
||||
int buffers;
|
||||
WCHAR** device_list;
|
||||
//dos=high, umb
|
||||
//device=%SystemRoot%\system32\himem.sys
|
||||
//files=40
|
||||
} VDM_CONFIG, *PVDM_CONFIG;
|
||||
|
||||
typedef struct tag_VDM_AUTOEXEC {
|
||||
WCHAR** load_list;
|
||||
//lh %SystemRoot%\system32\mscdexnt.exe
|
||||
//lh %SystemRoot%\system32\redir
|
||||
//lh %SystemRoot%\system32\dosx
|
||||
} VDM_AUTOEXEC, *PVDM_AUTOEXEC;
|
||||
|
||||
typedef struct tag_VDM_CONTROL_BLOCK {
|
||||
HANDLE hHeap;
|
||||
PVOID ImageMem;
|
||||
VDM_CONFIG vdmConfig;
|
||||
VDM_AUTOEXEC vdmAutoexec;
|
||||
PROCESS_INFORMATION ProcessInformation;
|
||||
CHAR CommandLine[MAX_PATH];
|
||||
CHAR CurrentDirectory[MAX_PATH];
|
||||
|
||||
} VDM_CONTROL_BLOCK, *PVDM_CONTROL_BLOCK;
|
||||
|
||||
|
||||
BOOL
|
||||
StartVDM(PVDM_CONTROL_BLOCK vdm)
|
||||
typedef struct _VDM_MENUITEM
|
||||
{
|
||||
BOOL Result;
|
||||
STARTUPINFOA StartupInfo;
|
||||
UINT uID;
|
||||
const struct _VDM_MENUITEM *SubMenu;
|
||||
WORD wCmdID;
|
||||
} VDM_MENUITEM, *PVDM_MENUITEM;
|
||||
|
||||
StartupInfo.cb = sizeof(StartupInfo);
|
||||
StartupInfo.lpReserved = NULL;
|
||||
StartupInfo.lpDesktop = NULL;
|
||||
StartupInfo.lpTitle = NULL;
|
||||
StartupInfo.dwFlags = 0;
|
||||
StartupInfo.cbReserved2 = 0;
|
||||
StartupInfo.lpReserved2 = 0;
|
||||
|
||||
Result = CreateProcessA(vdm->CommandLine,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
FALSE,
|
||||
DETACHED_PROCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
&StartupInfo,
|
||||
&vdm->ProcessInformation);
|
||||
if (!Result) {
|
||||
PrintString("VDM: Failed to execute target process\n");
|
||||
return FALSE;
|
||||
}
|
||||
WaitForSingleObject(vdm->ProcessInformation.hProcess, INFINITE);
|
||||
CloseHandle(vdm->ProcessInformation.hProcess);
|
||||
CloseHandle(vdm->ProcessInformation.hThread);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
ShutdownVDM(PVDM_CONTROL_BLOCK vdm)
|
||||
static const VDM_MENUITEM VdmMenuItems[] =
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
{ IDS_VDM_QUIT, NULL, ID_VDM_QUIT },
|
||||
|
||||
return result;
|
||||
}
|
||||
{ 0, NULL, 0 } /* End of list */
|
||||
};
|
||||
|
||||
BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm)
|
||||
static const VDM_MENUITEM VdmMainMenuItems[] =
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
DWORD dwError;
|
||||
HANDLE hFile;
|
||||
{ -1, NULL, 0 }, /* Separator */
|
||||
{ IDS_HIDE_MOUSE, NULL, ID_SHOWHIDE_MOUSE }, /* Hide mouse; can be renamed to Show mouse */
|
||||
{ IDS_VDM_MENU , VdmMenuItems, 0 }, /* ReactOS VDM Menu */
|
||||
|
||||
hFile = CreateFileW(L"\\system32\\config.nt",
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_ALWAYS /*OPEN_EXISTING*/,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0);
|
||||
dwError = GetLastError();
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
// error with file path or system problem?
|
||||
} else {
|
||||
if (dwError == 0L) {
|
||||
// we just created a new file, perhaps we should set/write some defaults?
|
||||
}
|
||||
if (dwError == ERROR_ALREADY_EXISTS) {
|
||||
// read the line entries and cache in some struct...
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
{ 0, NULL, 0 } /* End of list */
|
||||
};
|
||||
|
||||
hFile = CreateFileW(L"\\system32\\autoexec.nt",
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0);
|
||||
dwError = GetLastError();
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
// error with file path or system problem?
|
||||
} else {
|
||||
if (dwError == 0L) {
|
||||
// we just created a new file, perhaps we should set/write some defaults?
|
||||
}
|
||||
if (dwError == ERROR_ALREADY_EXISTS) {
|
||||
// read the line entries and cache in some struct...
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL
|
||||
LoadConfigDriversForVDM(PVDM_CONFIG vdmConfig)
|
||||
static VOID
|
||||
AppendMenuItems(HMENU hMenu,
|
||||
const VDM_MENUITEM *Items)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
UINT i = 0;
|
||||
WCHAR szMenuString[255];
|
||||
HMENU hSubMenu;
|
||||
|
||||
return result;
|
||||
}
|
||||
do
|
||||
{
|
||||
if (Items[i].uID != (UINT)-1)
|
||||
{
|
||||
if (LoadStringW(GetModuleHandle(NULL),
|
||||
Items[i].uID,
|
||||
szMenuString,
|
||||
sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
|
||||
{
|
||||
if (Items[i].SubMenu != NULL)
|
||||
{
|
||||
hSubMenu = CreatePopupMenu();
|
||||
if (hSubMenu != NULL)
|
||||
{
|
||||
AppendMenuItems(hSubMenu, Items[i].SubMenu);
|
||||
|
||||
BOOL
|
||||
SetConfigOptionsForVDM(PVDM_AUTOEXEC vdmAutoexec)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CreateVDM(PVDM_CONTROL_BLOCK vdm)
|
||||
{
|
||||
// BOOL result = TRUE;
|
||||
SYSTEM_INFO inf;
|
||||
MEMORYSTATUS stat;
|
||||
|
||||
|
||||
GlobalMemoryStatus(&stat);
|
||||
if (stat.dwLength != sizeof(MEMORYSTATUS)) {
|
||||
printf("WARNING: GlobalMemoryStatus() returned unknown structure version, size %ld, expected %d.\n", stat.dwLength, sizeof(stat));
|
||||
} else {
|
||||
printf("Memory Load: %ld percent in use.\n", stat.dwMemoryLoad);
|
||||
printf("\t%ld total bytes physical memory.\n", stat.dwTotalPhys);
|
||||
printf("\t%ld available physical memory.\n", stat.dwAvailPhys);
|
||||
printf("\t%ld total bytes paging file.\n", stat.dwTotalPageFile);
|
||||
printf("\t%ld available paging file.\n", stat.dwAvailPageFile);
|
||||
printf("\t%lx total bytes virtual memory.\n", stat.dwTotalVirtual);
|
||||
printf("\t%lx available bytes virtual memory.\n", stat.dwAvailVirtual);
|
||||
|
||||
#define OUT_OF_HEADROOM 90
|
||||
if (stat.dwMemoryLoad > OUT_OF_HEADROOM) {
|
||||
DPRINT("VDM: system resources deemed to low to start VDM.\n");
|
||||
//SetLastError();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GetSystemInfo(&inf);
|
||||
vdm->hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
|
||||
if (vdm->hHeap == NULL) {
|
||||
DPRINT("VDM: failed to create heap.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define DEFAULT_VDM_IMAGE_SIZE 2000000
|
||||
vdm->ImageMem = HeapAlloc(vdm->hHeap, 0, DEFAULT_VDM_IMAGE_SIZE);
|
||||
if (vdm->ImageMem == NULL) {
|
||||
DPRINT("VDM: failed to allocate image memory from heap %x.\n", vdm->hHeap);
|
||||
HeapDestroy(vdm->hHeap);
|
||||
vdm->hHeap = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
DestroyVDM(PVDM_CONTROL_BLOCK vdm)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
|
||||
if (vdm->ImageMem != NULL) {
|
||||
if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) {
|
||||
DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap);
|
||||
result = FALSE;
|
||||
}
|
||||
vdm->ImageMem = NULL;
|
||||
}
|
||||
if (vdm->hHeap != NULL) {
|
||||
if (!HeapDestroy(vdm->hHeap)) {
|
||||
DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap);
|
||||
result = FALSE;
|
||||
}
|
||||
vdm->hHeap = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||
{
|
||||
VDM_CONTROL_BLOCK VdmCB;
|
||||
DWORD Result;
|
||||
ULONG i;
|
||||
BOOL vdmStarted = FALSE;
|
||||
|
||||
WCHAR WelcomeMsg[RC_STRING_MAX_SIZE];
|
||||
WCHAR PromptMsg[RC_STRING_MAX_SIZE];
|
||||
CHAR InputBuffer[255];
|
||||
|
||||
LoadStringW( GetModuleHandle(NULL), STRING_WelcomeMsg, WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0]));
|
||||
LoadStringW( GetModuleHandle(NULL), STRING_PromptMsg, PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0]));
|
||||
|
||||
AllocConsole();
|
||||
SetConsoleTitleW(L"ntvdm");
|
||||
|
||||
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
WelcomeMsg, lstrlenW(WelcomeMsg), // wcslen(WelcomeMsg),
|
||||
&Result, NULL);
|
||||
|
||||
if (!CreateVDM(&VdmCB)) {
|
||||
DPRINT("VDM: failed to create VDM.\n");
|
||||
//SetLastError();
|
||||
return 2;
|
||||
}
|
||||
|
||||
ReadConfigForVDM(&VdmCB);
|
||||
|
||||
if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) {
|
||||
DPRINT("VDM: failed to load configuration drivers.\n");
|
||||
//SetLastError();
|
||||
return 2;
|
||||
}
|
||||
if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) {
|
||||
DPRINT("VDM: failed to set configuration options.\n");
|
||||
//SetLastError();
|
||||
return 3;
|
||||
}
|
||||
|
||||
GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH);
|
||||
strcat(VdmCB.CommandLine, "\\hello.exe");
|
||||
GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH);
|
||||
|
||||
for (;;) {
|
||||
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
|
||||
PromptMsg, lstrlenW(PromptMsg), // wcslen(PromptMsg),
|
||||
&Result, NULL);
|
||||
i = 0;
|
||||
do {
|
||||
ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
|
||||
&InputBuffer[i], 1,
|
||||
&Result, NULL);
|
||||
if (++i >= (sizeof(InputBuffer) - 1)) {
|
||||
break;
|
||||
}
|
||||
} while (InputBuffer[i - 1] != '\n');
|
||||
InputBuffer[i - 1] = '\0';
|
||||
|
||||
if (InputBuffer[0] == 'r' || InputBuffer[0] == 'R') {
|
||||
if (!vdmStarted) {
|
||||
if (StartVDM(&VdmCB)) {
|
||||
vdmStarted = TRUE;
|
||||
} else {
|
||||
DPRINT("VDM: failed to start.\n");
|
||||
if (!AppendMenuW(hMenu,
|
||||
MF_STRING | MF_POPUP,
|
||||
(UINT_PTR)hSubMenu,
|
||||
szMenuString))
|
||||
{
|
||||
DestroyMenu(hSubMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DPRINT("VDM: already started.\n");
|
||||
}
|
||||
}
|
||||
if (InputBuffer[0] == 's' || InputBuffer[0] == 'S') {
|
||||
if (vdmStarted) {
|
||||
if (ShutdownVDM(&VdmCB)) {
|
||||
vdmStarted = FALSE;
|
||||
} else {
|
||||
DPRINT("VDM: failed to shutdown.\n");
|
||||
else
|
||||
{
|
||||
AppendMenuW(hMenu,
|
||||
MF_STRING,
|
||||
Items[i].wCmdID,
|
||||
szMenuString);
|
||||
}
|
||||
} else {
|
||||
DPRINT("VDM: not started.\n");
|
||||
}
|
||||
}
|
||||
if (InputBuffer[0] == 'q' || InputBuffer[0] == 'Q') {
|
||||
else
|
||||
{
|
||||
AppendMenuW(hMenu,
|
||||
MF_SEPARATOR,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
i++;
|
||||
} while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
|
||||
}
|
||||
|
||||
static VOID
|
||||
CreateVdmMenu(HANDLE ConOutHandle)
|
||||
{
|
||||
hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
|
||||
ID_SHOWHIDE_MOUSE,
|
||||
ID_VDM_QUIT);
|
||||
if (hConsoleMenu == NULL) return;
|
||||
|
||||
VdmMenuPos = GetMenuItemCount(hConsoleMenu);
|
||||
AppendMenuItems(hConsoleMenu, VdmMainMenuItems);
|
||||
DrawMenuBar(GetConsoleWindow());
|
||||
}
|
||||
|
||||
static VOID
|
||||
DestroyVdmMenu(VOID)
|
||||
{
|
||||
UINT i = 0;
|
||||
const VDM_MENUITEM *Items = VdmMainMenuItems;
|
||||
|
||||
do
|
||||
{
|
||||
DeleteMenu(hConsoleMenu, VdmMenuPos, MF_BYPOSITION);
|
||||
i++;
|
||||
} while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
|
||||
|
||||
DrawMenuBar(GetConsoleWindow());
|
||||
}
|
||||
|
||||
static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
|
||||
{
|
||||
WCHAR szMenuString[255] = L"";
|
||||
|
||||
if (ShowPtr)
|
||||
{
|
||||
/* Be sure the cursor will be shown */
|
||||
while (ShowConsoleCursor(ConOutHandle, TRUE) < 0) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Be sure the cursor will be hidden */
|
||||
while (ShowConsoleCursor(ConOutHandle, FALSE) >= 0) ;
|
||||
}
|
||||
|
||||
if (LoadStringW(GetModuleHandle(NULL),
|
||||
(!ShowPtr ? IDS_SHOW_MOUSE : IDS_HIDE_MOUSE),
|
||||
szMenuString,
|
||||
sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
|
||||
{
|
||||
ModifyMenu(hConsoleMenu, ID_SHOWHIDE_MOUSE,
|
||||
MF_BYCOMMAND, ID_SHOWHIDE_MOUSE, szMenuString);
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
VOID DisplayMessage(LPCWSTR Format, ...)
|
||||
{
|
||||
WCHAR Buffer[256];
|
||||
va_list Parameters;
|
||||
|
||||
va_start(Parameters, Format);
|
||||
_vsnwprintf(Buffer, 256, Format, Parameters);
|
||||
DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
|
||||
MessageBoxW(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
|
||||
va_end(Parameters);
|
||||
}
|
||||
|
||||
BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
|
||||
{
|
||||
switch (ControlType)
|
||||
{
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
{
|
||||
/* Call INT 23h */
|
||||
EmulatorInterrupt(0x23);
|
||||
break;
|
||||
}
|
||||
case CTRL_LAST_CLOSE_EVENT:
|
||||
{
|
||||
if (WaitForSingleObject(VdmTaskEvent, 0) == WAIT_TIMEOUT)
|
||||
{
|
||||
/* Exit immediately */
|
||||
if (CommandThread) TerminateThread(CommandThread, 0);
|
||||
EmulatorTerminate();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop accepting new commands */
|
||||
AcceptCommands = FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* Stop the VDM if the user logs out or closes the console */
|
||||
EmulatorTerminate();
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID ConsoleInitUI(VOID)
|
||||
{
|
||||
CreateVdmMenu(ConsoleOutput);
|
||||
}
|
||||
|
||||
VOID ConsoleCleanupUI(VOID)
|
||||
{
|
||||
/* Display again properly the mouse pointer */
|
||||
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
||||
|
||||
DestroyVdmMenu();
|
||||
}
|
||||
|
||||
DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
|
||||
{
|
||||
HANDLE ConsoleInput = (HANDLE)Parameter;
|
||||
INPUT_RECORD InputRecord;
|
||||
DWORD Count;
|
||||
|
||||
while (VdmRunning)
|
||||
{
|
||||
/* Make sure the task event is signaled */
|
||||
WaitForSingleObject(VdmTaskEvent, INFINITE);
|
||||
|
||||
/* Wait for an input record */
|
||||
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
|
||||
{
|
||||
DWORD LastError = GetLastError();
|
||||
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
|
||||
return LastError;
|
||||
}
|
||||
|
||||
ASSERT(Count != 0);
|
||||
|
||||
/* Check the event type */
|
||||
switch (InputRecord.EventType)
|
||||
{
|
||||
case KEY_EVENT:
|
||||
case MOUSE_EVENT:
|
||||
/* Send it to the PS/2 controller */
|
||||
PS2Dispatch(&InputRecord);
|
||||
break;
|
||||
|
||||
case MENU_EVENT:
|
||||
{
|
||||
switch (InputRecord.Event.MenuEvent.dwCommandId)
|
||||
{
|
||||
case ID_SHOWHIDE_MOUSE:
|
||||
ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
||||
ShowPointer = !ShowPointer;
|
||||
break;
|
||||
|
||||
case ID_VDM_QUIT:
|
||||
/* Stop the VDM */
|
||||
EmulatorTerminate();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ShutdownVDM(&VdmCB)) {
|
||||
DPRINT("VDM: failed to cleanly shutdown VDM.\n");
|
||||
//SetLastError();
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (!DestroyVDM(&VdmCB)) {
|
||||
DPRINT("VDM: failed to cleanly destroy VDM.\n");
|
||||
//SetLastError();
|
||||
return 6;
|
||||
}
|
||||
|
||||
ExitProcess(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL ConsoleInit(VOID)
|
||||
{
|
||||
/* Set the handler routine */
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
|
||||
/* Enable the CTRL_LAST_CLOSE_EVENT */
|
||||
SetLastConsoleEventActive();
|
||||
|
||||
/* Get the input handle to the real console, and check for success */
|
||||
ConsoleInput = CreateFileW(L"CONIN$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
if (ConsoleInput == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wprintf(L"FATAL: Cannot retrieve a handle to the console input\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Get the output handle to the real console, and check for success */
|
||||
ConsoleOutput = CreateFileW(L"CONOUT$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
if (ConsoleOutput == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(ConsoleInput);
|
||||
wprintf(L"FATAL: Cannot retrieve a handle to the console output\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Save the original input and output console modes */
|
||||
if (!GetConsoleMode(ConsoleInput , &OrgConsoleInputMode ) ||
|
||||
!GetConsoleMode(ConsoleOutput, &OrgConsoleOutputMode))
|
||||
{
|
||||
CloseHandle(ConsoleOutput);
|
||||
CloseHandle(ConsoleInput);
|
||||
wprintf(L"FATAL: Cannot save console in/out modes\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Initialize the UI */
|
||||
ConsoleInitUI();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID ConsoleCleanup(VOID)
|
||||
{
|
||||
/* Restore the original input and output console modes */
|
||||
SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
|
||||
SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
|
||||
|
||||
/* Cleanup the UI */
|
||||
ConsoleCleanupUI();
|
||||
|
||||
/* Close the console handles */
|
||||
if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
|
||||
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
|
||||
}
|
||||
|
||||
DWORD WINAPI CommandThreadProc(LPVOID Parameter)
|
||||
{
|
||||
BOOLEAN First = TRUE;
|
||||
DWORD Result;
|
||||
VDM_COMMAND_INFO CommandInfo;
|
||||
CHAR CmdLine[MAX_PATH];
|
||||
CHAR AppName[MAX_PATH];
|
||||
CHAR PifFile[MAX_PATH];
|
||||
CHAR Desktop[MAX_PATH];
|
||||
CHAR Title[MAX_PATH];
|
||||
CHAR Env[MAX_PATH];
|
||||
|
||||
UNREFERENCED_PARAMETER(Parameter);
|
||||
|
||||
do
|
||||
{
|
||||
/* Clear the structure */
|
||||
ZeroMemory(&CommandInfo, sizeof(CommandInfo));
|
||||
|
||||
/* Initialize the structure members */
|
||||
CommandInfo.TaskId = SessionId;
|
||||
CommandInfo.VDMState = VDM_FLAG_DOS;
|
||||
CommandInfo.CmdLine = CmdLine;
|
||||
CommandInfo.CmdLen = sizeof(CmdLine);
|
||||
CommandInfo.AppName = AppName;
|
||||
CommandInfo.AppLen = sizeof(AppName);
|
||||
CommandInfo.PifFile = PifFile;
|
||||
CommandInfo.PifLen = sizeof(PifFile);
|
||||
CommandInfo.Desktop = Desktop;
|
||||
CommandInfo.DesktopLen = sizeof(Desktop);
|
||||
CommandInfo.Title = Title;
|
||||
CommandInfo.TitleLen = sizeof(Title);
|
||||
CommandInfo.Env = Env;
|
||||
CommandInfo.EnvLen = sizeof(Env);
|
||||
|
||||
if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
|
||||
|
||||
/* Wait for the next available VDM */
|
||||
if (!GetNextVDMCommand(&CommandInfo)) break;
|
||||
|
||||
/* Start the process from the command line */
|
||||
DPRINT1("Starting '%s'...\n", AppName);
|
||||
|
||||
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, AppName, CmdLine, Env, NULL, NULL);
|
||||
if (Result != ERROR_SUCCESS)
|
||||
{
|
||||
DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Attach to the console */
|
||||
if (!First) VgaAttachToConsole();
|
||||
|
||||
/* Perform a screen refresh */
|
||||
VgaRefreshDisplay();
|
||||
|
||||
/* Start simulation */
|
||||
SetEvent(VdmTaskEvent);
|
||||
EmulatorSimulate();
|
||||
|
||||
/* Perform another screen refresh */
|
||||
VgaRefreshDisplay();
|
||||
|
||||
/* Detach from the console */
|
||||
VgaDetachFromConsole(FALSE);
|
||||
|
||||
First = FALSE;
|
||||
}
|
||||
while (AcceptCommands);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT wmain(INT argc, WCHAR *argv[])
|
||||
{
|
||||
#ifdef STANDALONE
|
||||
|
||||
DWORD Result;
|
||||
CHAR ApplicationName[MAX_PATH];
|
||||
CHAR CommandLine[DOS_CMDLINE_LENGTH];
|
||||
|
||||
if (argc >= 2)
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, 0, argv[1], -1, ApplicationName, sizeof(ApplicationName), NULL, NULL);
|
||||
|
||||
if (argc >= 3) WideCharToMultiByte(CP_ACP, 0, argv[2], -1, CommandLine, sizeof(CommandLine), NULL, NULL);
|
||||
else strcpy(CommandLine, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
wprintf(L"\nReactOS Virtual DOS Machine\n\n"
|
||||
L"Usage: NTVDM <executable> [<parameters>]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
INT i;
|
||||
WCHAR *endptr;
|
||||
|
||||
/* Parse the command line arguments */
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (wcsncmp(argv[i], L"-i", 2) == 0)
|
||||
{
|
||||
/* This is the session ID */
|
||||
SessionId = wcstoul(argv[i] + 2, &endptr, 10);
|
||||
|
||||
/* The VDM hasn't been started from a console, so quit when the task is done */
|
||||
AcceptCommands = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
|
||||
|
||||
/* Create the task event */
|
||||
VdmTaskEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
ASSERT(VdmTaskEvent != NULL);
|
||||
|
||||
/* Initialize the console */
|
||||
if (!ConsoleInit())
|
||||
{
|
||||
wprintf(L"FATAL: A problem occurred when trying to initialize the console\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Initialize the emulator */
|
||||
if (!EmulatorInitialize(ConsoleInput, ConsoleOutput))
|
||||
{
|
||||
wprintf(L"FATAL: Failed to initialize the emulator\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Initialize the system BIOS */
|
||||
if (!BiosInitialize(NULL))
|
||||
{
|
||||
wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Initialize the VDM DOS kernel */
|
||||
if (!DosInitialize(NULL))
|
||||
{
|
||||
wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
#ifndef STANDALONE
|
||||
|
||||
/* Create the GetNextVDMCommand thread */
|
||||
CommandThread = CreateThread(NULL, 0, &CommandThreadProc, NULL, 0, NULL);
|
||||
if (CommandThread == NULL)
|
||||
{
|
||||
wprintf(L"FATAL: Failed to create the command processing thread: %d\n", GetLastError());
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Wait for the command thread to exit */
|
||||
WaitForSingleObject(CommandThread, INFINITE);
|
||||
|
||||
/* Close the thread handle */
|
||||
CloseHandle(CommandThread);
|
||||
|
||||
#else
|
||||
|
||||
/* Start the process from the command line */
|
||||
DPRINT1("Starting '%s'...\n", ApplicationName);
|
||||
|
||||
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
|
||||
ApplicationName,
|
||||
CommandLine,
|
||||
GetEnvironmentStrings(),
|
||||
NULL,
|
||||
NULL);
|
||||
if (Result != ERROR_SUCCESS)
|
||||
{
|
||||
DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Start simulation */
|
||||
SetEvent(VdmTaskEvent);
|
||||
EmulatorSimulate();
|
||||
|
||||
/* Perform another screen refresh */
|
||||
VgaRefreshDisplay();
|
||||
|
||||
#endif
|
||||
|
||||
Cleanup:
|
||||
BiosCleanup();
|
||||
EmulatorCleanup();
|
||||
ConsoleCleanup();
|
||||
|
||||
#ifndef STANDALONE
|
||||
ExitVDM(FALSE, 0);
|
||||
#endif
|
||||
|
||||
/* Quit the VDM */
|
||||
DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: ntvdm.h
|
||||
* PURPOSE: Header file to define commonly used stuff
|
||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||
*/
|
||||
|
||||
#ifndef _NTVDM_H_
|
||||
#define _NTVDM_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <conio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <wingdi.h>
|
||||
#include <wincon.h>
|
||||
#include <winnls.h>
|
||||
#include <winreg.h>
|
||||
#include <winuser.h>
|
||||
#include <subsys/win/vdm.h>
|
||||
|
||||
#include <vddsvc.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
DWORD WINAPI SetLastConsoleEventActive(VOID);
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
extern ULONG SessionId;
|
||||
extern HANDLE VdmTaskEvent;
|
||||
|
||||
VOID DisplayMessage(LPCWSTR Format, ...);
|
||||
|
||||
#endif // _NTVDM_H_
|
||||
|
||||
/* EOF */
|
||||
@@ -1,32 +1,39 @@
|
||||
#include <windef.h>
|
||||
#include <winuser.h>
|
||||
// #include <commctrl.h>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Virtual DOS Machine"
|
||||
#define REACTOS_STR_INTERNAL_NAME "ntvdm"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "ntvdm.exe"
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Virtual DOS Machine"
|
||||
#define REACTOS_STR_INTERNAL_NAME "ntvdm"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "ntvdm.exe"
|
||||
#include <reactos/version.rc>
|
||||
|
||||
IDI_APPICON ICON "res/ntvdm.ico"
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
#include "lang/bg-BG.rc"
|
||||
#include "lang/cs-CZ.rc"
|
||||
#include "lang/de-DE.rc"
|
||||
#include "lang/en-US.rc"
|
||||
#include "lang/es-ES.rc"
|
||||
#include "lang/fr-FR.rc"
|
||||
#include "lang/hu-HU.rc"
|
||||
#include "lang/id-ID.rc"
|
||||
#include "lang/it-IT.rc"
|
||||
#include "lang/ja-JP.rc"
|
||||
#include "lang/no-NO.rc"
|
||||
#include "lang/pl-PL.rc"
|
||||
#include "lang/pt-BR.rc"
|
||||
#include "lang/ro-RO.rc"
|
||||
#include "lang/ru-RU.rc"
|
||||
#include "lang/sk-SK.rc"
|
||||
#include "lang/th-TH.rc"
|
||||
#include "lang/uk-UA.rc"
|
||||
#include "lang/zh-CN.rc"
|
||||
#include "lang/zh-TW.rc"
|
||||
#ifdef LANGUAGE_CS_CZ
|
||||
#include "lang/cs-CZ.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_DE_DE
|
||||
#include "lang/de-DE.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_EN_US
|
||||
#include "lang/en-US.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_ES_ES
|
||||
#include "lang/es-ES.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_FR_FR
|
||||
#include "lang/fr-FR.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_IT_IT
|
||||
#include "lang/it-IT.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_PL_PL
|
||||
#include "lang/pl-PL.rc"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; NTVDM Registers exports ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@ stdcall getAF()
|
||||
@ stdcall getAH()
|
||||
@ stdcall getAL()
|
||||
@ stdcall getAX()
|
||||
@ stdcall getBH()
|
||||
@ stdcall getBL()
|
||||
@ stdcall getBP()
|
||||
@ stdcall getBX()
|
||||
@ stdcall getCF()
|
||||
@ stdcall getCH()
|
||||
@ stdcall getCL()
|
||||
@ stdcall getCS()
|
||||
@ stdcall getCX()
|
||||
@ stdcall getDF()
|
||||
@ stdcall getDH()
|
||||
@ stdcall getDI()
|
||||
@ stdcall getDL()
|
||||
@ stdcall getDS()
|
||||
@ stdcall getDX()
|
||||
@ stdcall getEAX()
|
||||
@ stdcall getEBP()
|
||||
@ stdcall getEBX()
|
||||
@ stdcall getECX()
|
||||
@ stdcall getEDI()
|
||||
@ stdcall getEDX()
|
||||
@ stdcall getEFLAGS()
|
||||
@ stdcall getEIP()
|
||||
@ stdcall getES()
|
||||
@ stdcall getESI()
|
||||
@ stdcall getESP()
|
||||
@ stdcall getFS()
|
||||
@ stdcall getGS()
|
||||
@ stdcall getIF()
|
||||
@ stdcall getIntelRegistersPointer()
|
||||
@ stdcall getIP()
|
||||
@ stdcall getMSW()
|
||||
@ stdcall getOF()
|
||||
@ stdcall getPF()
|
||||
@ stdcall getSF()
|
||||
@ stdcall getSI()
|
||||
@ stdcall getSP()
|
||||
@ stdcall getSS()
|
||||
@ stdcall getZF()
|
||||
|
||||
@ stdcall setAF(long)
|
||||
@ stdcall setAH(long)
|
||||
@ stdcall setAL(long)
|
||||
@ stdcall setAX(long)
|
||||
@ stdcall setBH(long)
|
||||
@ stdcall setBL(long)
|
||||
@ stdcall setBP(long)
|
||||
@ stdcall setBX(long)
|
||||
@ stdcall setCF(long)
|
||||
@ stdcall setCH(long)
|
||||
@ stdcall setCL(long)
|
||||
@ stdcall setCS(long)
|
||||
@ stdcall setCX(long)
|
||||
@ stdcall setDF(long)
|
||||
@ stdcall setDH(long)
|
||||
@ stdcall setDI(long)
|
||||
@ stdcall setDL(long)
|
||||
@ stdcall setDS(long)
|
||||
@ stdcall setDX(long)
|
||||
@ stdcall setEAX(long)
|
||||
@ stdcall setEBP(long)
|
||||
@ stdcall setEBX(long)
|
||||
@ stdcall setECX(long)
|
||||
@ stdcall setEDI(long)
|
||||
@ stdcall setEDX(long)
|
||||
@ stdcall setEFLAGS(long)
|
||||
@ stdcall setEIP(long)
|
||||
@ stdcall setES(long)
|
||||
@ stdcall setESI(long)
|
||||
@ stdcall setESP(long)
|
||||
@ stdcall setFS(long)
|
||||
@ stdcall setGS(long)
|
||||
@ stdcall setIF(long)
|
||||
@ stdcall setIP(long)
|
||||
@ stdcall setMSW(long)
|
||||
@ stdcall setOF(long)
|
||||
@ stdcall setPF(long)
|
||||
@ stdcall setSF(long)
|
||||
@ stdcall setSI(long)
|
||||
@ stdcall setSP(long)
|
||||
@ stdcall setSS(long)
|
||||
@ stdcall setZF(long)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; NTVDM CCPU MIPS exports ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@ stdcall c_getAF() getAF
|
||||
@ stdcall c_getAH() getAH
|
||||
@ stdcall c_getAL() getAL
|
||||
@ stdcall c_getAX() getAX
|
||||
@ stdcall c_getBH() getBH
|
||||
@ stdcall c_getBL() getBL
|
||||
@ stdcall c_getBP() getBP
|
||||
@ stdcall c_getBX() getBX
|
||||
@ stdcall c_getCF() getCF
|
||||
@ stdcall c_getCH() getCH
|
||||
@ stdcall c_getCL() getCL
|
||||
@ stdcall c_getCS() getCS
|
||||
@ stdcall c_getCX() getCX
|
||||
@ stdcall c_getDF() getDF
|
||||
@ stdcall c_getDH() getDH
|
||||
@ stdcall c_getDI() getDI
|
||||
@ stdcall c_getDL() getDL
|
||||
@ stdcall c_getDS() getDS
|
||||
@ stdcall c_getDX() getDX
|
||||
@ stdcall c_getEAX() getEAX
|
||||
@ stdcall c_getEBP() getEBP
|
||||
@ stdcall c_getEBX() getEBX
|
||||
@ stdcall c_getECX() getECX
|
||||
@ stdcall c_getEDI() getEDI
|
||||
@ stdcall c_getEDX() getEDX
|
||||
@ stdcall c_getEIP() getEIP
|
||||
@ stdcall c_getES() getES
|
||||
@ stdcall c_getESI() getESI
|
||||
@ stdcall c_getESP() getESP
|
||||
@ stdcall c_getFS() getFS
|
||||
@ stdcall c_getGS() getGS
|
||||
@ stdcall c_getIF() getIF
|
||||
@ stdcall c_getIP() getIP
|
||||
@ stdcall c_getMSW() getMSW
|
||||
@ stdcall c_getOF() getOF
|
||||
@ stdcall c_getPF() getPF
|
||||
@ stdcall c_getSF() getSF
|
||||
@ stdcall c_getSI() getSI
|
||||
@ stdcall c_getSP() getSP
|
||||
@ stdcall c_getSS() getSS
|
||||
@ stdcall c_getZF() getZF
|
||||
|
||||
@ stdcall c_setAF(long) setAF
|
||||
@ stdcall c_setAH(long) setAH
|
||||
@ stdcall c_setAL(long) setAL
|
||||
@ stdcall c_setAX(long) setAX
|
||||
@ stdcall c_setBH(long) setBH
|
||||
@ stdcall c_setBL(long) setBL
|
||||
@ stdcall c_setBP(long) setBP
|
||||
@ stdcall c_setBX(long) setBX
|
||||
@ stdcall c_setCF(long) setCF
|
||||
@ stdcall c_setCH(long) setCH
|
||||
@ stdcall c_setCL(long) setCL
|
||||
@ stdcall c_setCS(long) setCS
|
||||
@ stdcall c_setCX(long) setCX
|
||||
@ stdcall c_setDF(long) setDF
|
||||
@ stdcall c_setDH(long) setDH
|
||||
@ stdcall c_setDI(long) setDI
|
||||
@ stdcall c_setDL(long) setDL
|
||||
@ stdcall c_setDS(long) setDS
|
||||
@ stdcall c_setDX(long) setDX
|
||||
@ stdcall c_setEAX(long) setEAX
|
||||
@ stdcall c_setEBP(long) setEBP
|
||||
@ stdcall c_setEBX(long) setEBX
|
||||
@ stdcall c_setECX(long) setECX
|
||||
@ stdcall c_setEDI(long) setEDI
|
||||
@ stdcall c_setEDX(long) setEDX
|
||||
@ stdcall c_setEIP(long) setEIP
|
||||
@ stdcall c_setES(long) setES
|
||||
@ stdcall c_setESI(long) setESI
|
||||
@ stdcall c_setESP(long) setESP
|
||||
@ stdcall c_setFS(long) setFS
|
||||
@ stdcall c_setGS(long) setGS
|
||||
@ stdcall c_setIF(long) setIF
|
||||
@ stdcall c_setIP(long) setIP
|
||||
@ stdcall c_setMSW(long) setMSW
|
||||
@ stdcall c_setOF(long) setOF
|
||||
@ stdcall c_setPF(long) setPF
|
||||
@ stdcall c_setSF(long) setSF
|
||||
@ stdcall c_setSI(long) setSI
|
||||
@ stdcall c_setSP(long) setSP
|
||||
@ stdcall c_setSS(long) setSS
|
||||
@ stdcall c_setZF(long) setZF
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; NTVDM DOS-32 Emulation exports ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@ stdcall demClientErrorEx(long long long)
|
||||
@ stdcall demFileDelete(ptr)
|
||||
@ stdcall demFileFindFirst(ptr ptr long)
|
||||
@ stdcall demFileFindNext(ptr)
|
||||
;@ stdcall demGetFileTimeByHandle_WOW
|
||||
@ stdcall demGetPhysicalDriveType(long)
|
||||
@ stdcall demIsShortPathName(ptr long)
|
||||
;@ stdcall demLFNCleanup
|
||||
;@ stdcall demLFNGetCurrentDirectory
|
||||
@ stdcall demSetCurrentDirectoryGetDrive(ptr ptr)
|
||||
;@ stdcall demWOWLFNAllocateSearchHandle
|
||||
;@ stdcall demWOWLFNCloseSearchHandle
|
||||
;@ stdcall demWOWLFNEntry
|
||||
;@ stdcall demWOWLFNGetSearchHandle
|
||||
;@ stdcall demWOWLFNInit
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; NTVDM Miscellaneous exports ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@ stdcall MGetVdmPointer(long long long)
|
||||
@ stdcall Sim32pGetVDMPointer(long long)
|
||||
|
||||
;@ stdcall VdmFlushCache(long long long long) ; Not exported on x86
|
||||
@ stdcall VdmMapFlat(long long long)
|
||||
;@ stdcall VdmUnmapFlat(long long ptr long) ; Not exported on x86
|
||||
|
||||
@ stdcall call_ica_hw_interrupt(long long long)
|
||||
@ stdcall VDDInstallIOHook(long long ptr ptr)
|
||||
@ stdcall VDDDeInstallIOHook(long long ptr)
|
||||
|
||||
@ stdcall VDDSimulate16()
|
||||
@ stdcall host_simulate() VDDSimulate16
|
||||
@ stdcall VDDTerminateVDM()
|
||||
@@ -0,0 +1,683 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: registers.c
|
||||
* PURPOSE: Exported functions for manipulating registers
|
||||
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#define NDEBUG
|
||||
|
||||
#include "emulator.h"
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
static inline BOOLEAN EmulatorGetFlag(ULONG Flag)
|
||||
{
|
||||
return (EmulatorContext.Flags.Long & Flag) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static inline VOID EmulatorSetFlag(ULONG Flag)
|
||||
{
|
||||
EmulatorContext.Flags.Long |= Flag;
|
||||
}
|
||||
|
||||
static inline VOID EmulatorClearFlag(ULONG Flag)
|
||||
{
|
||||
EmulatorContext.Flags.Long &= ~Flag;
|
||||
}
|
||||
|
||||
VOID EmulatorSetStack(WORD Segment, DWORD Offset)
|
||||
{
|
||||
Fast486SetStack(&EmulatorContext, Segment, Offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PVOID
|
||||
WINAPI
|
||||
getIntelRegistersPointer(VOID)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getEAX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EAX].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setEAX(ULONG Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EAX].Long = Value;
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getAX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EAX].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setAX(USHORT Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EAX].LowWord = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getAH(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EAX].HighByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setAH(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EAX].HighByte = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getAL(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EAX].LowByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setAL(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EAX].LowByte = Value;
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getEBX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EBX].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setEBX(ULONG Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EBX].Long = Value;
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getBX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EBX].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setBX(USHORT Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EBX].LowWord = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getBH(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EBX].HighByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setBH(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EBX].HighByte = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getBL(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EBX].LowByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setBL(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EBX].LowByte = Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getECX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ECX].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setECX(ULONG Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_ECX].Long = Value;
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getCX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ECX].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setCX(USHORT Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_ECX].LowWord = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getCH(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ECX].HighByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setCH(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_ECX].HighByte = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getCL(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ECX].LowByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setCL(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_ECX].LowByte = Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getEDX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EDX].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setEDX(ULONG Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EDX].Long = Value;
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getDX(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EDX].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setDX(USHORT Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EDX].LowWord = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getDH(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EDX].HighByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setDH(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EDX].HighByte = Value;
|
||||
}
|
||||
|
||||
UCHAR
|
||||
WINAPI
|
||||
getDL(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EDX].LowByte;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setDL(UCHAR Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EDX].LowByte = Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getESP(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ESP].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setESP(ULONG Value)
|
||||
{
|
||||
EmulatorSetStack(getSS(), Value);
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getSP(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ESP].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setSP(USHORT Value)
|
||||
{
|
||||
EmulatorSetStack(getSS(), Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getEBP(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EBP].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setEBP(ULONG Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EBP].Long = Value;
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getBP(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EBP].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setBP(USHORT Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EBP].LowWord = Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getESI(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ESI].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setESI(ULONG Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_ESI].Long = Value;
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getSI(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_ESI].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setSI(USHORT Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_ESI].LowWord = Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getEDI(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EDI].Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setEDI(ULONG Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EDI].Long = Value;
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getDI(VOID)
|
||||
{
|
||||
return EmulatorContext.GeneralRegs[FAST486_REG_EDI].LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setDI(USHORT Value)
|
||||
{
|
||||
EmulatorContext.GeneralRegs[FAST486_REG_EDI].LowWord = Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getEIP(VOID)
|
||||
{
|
||||
return EmulatorContext.InstPtr.Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setEIP(ULONG Value)
|
||||
{
|
||||
EmulatorExecute(getCS(), Value);
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getIP(VOID)
|
||||
{
|
||||
return EmulatorContext.InstPtr.LowWord;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setIP(USHORT Value)
|
||||
{
|
||||
EmulatorExecute(getCS(), Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getCS(VOID)
|
||||
{
|
||||
return EmulatorContext.SegmentRegs[FAST486_REG_CS].Selector;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setCS(USHORT Value)
|
||||
{
|
||||
Fast486SetSegment(&EmulatorContext, FAST486_REG_CS, Value);
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getSS(VOID)
|
||||
{
|
||||
return EmulatorContext.SegmentRegs[FAST486_REG_SS].Selector;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setSS(USHORT Value)
|
||||
{
|
||||
Fast486SetSegment(&EmulatorContext, FAST486_REG_SS, Value);
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getDS(VOID)
|
||||
{
|
||||
return EmulatorContext.SegmentRegs[FAST486_REG_DS].Selector;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setDS(USHORT Value)
|
||||
{
|
||||
Fast486SetSegment(&EmulatorContext, FAST486_REG_DS, Value);
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getES(VOID)
|
||||
{
|
||||
return EmulatorContext.SegmentRegs[FAST486_REG_ES].Selector;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setES(USHORT Value)
|
||||
{
|
||||
Fast486SetSegment(&EmulatorContext, FAST486_REG_ES, Value);
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getFS(VOID)
|
||||
{
|
||||
return EmulatorContext.SegmentRegs[FAST486_REG_FS].Selector;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setFS(USHORT Value)
|
||||
{
|
||||
Fast486SetSegment(&EmulatorContext, FAST486_REG_FS, Value);
|
||||
}
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getGS(VOID)
|
||||
{
|
||||
return EmulatorContext.SegmentRegs[FAST486_REG_GS].Selector;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setGS(USHORT Value)
|
||||
{
|
||||
Fast486SetSegment(&EmulatorContext, FAST486_REG_GS, Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getCF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_CF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setCF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_CF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_CF);
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getPF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_PF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setPF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_PF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_PF);
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getAF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_AF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setAF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_AF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_AF);
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getZF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_ZF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setZF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_ZF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_ZF);
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getSF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_SF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setSF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_SF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_SF);
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getIF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_IF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setIF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_IF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_IF);
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getDF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_DF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setDF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_DF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_DF);
|
||||
}
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getOF(VOID)
|
||||
{
|
||||
return EmulatorGetFlag(EMULATOR_FLAG_OF);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setOF(ULONG Flag)
|
||||
{
|
||||
if (Flag & 1)
|
||||
EmulatorSetFlag(EMULATOR_FLAG_OF);
|
||||
else
|
||||
EmulatorClearFlag(EMULATOR_FLAG_OF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ULONG
|
||||
WINAPI
|
||||
getEFLAGS(VOID)
|
||||
{
|
||||
return EmulatorContext.Flags.Long;
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setEFLAGS(ULONG Flags)
|
||||
{
|
||||
EmulatorContext.Flags.Long = Flags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
USHORT
|
||||
WINAPI
|
||||
getMSW(VOID)
|
||||
{
|
||||
return LOWORD(EmulatorContext.ControlRegisters[FAST486_REG_CR0]);
|
||||
}
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
setMSW(USHORT Value)
|
||||
{
|
||||
/* Set the lower 16 bits (Machine Status Word) of CR0 */
|
||||
EmulatorContext.ControlRegisters[FAST486_REG_CR0] &= 0xFFFF0000;
|
||||
EmulatorContext.ControlRegisters[FAST486_REG_CR0] |= Value & 0xFFFF;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Virtual DOS Machine
|
||||
* FILE: registers.c
|
||||
* PURPOSE: Exported functions for manipulating registers
|
||||
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
#ifndef _REGISTERS_H_
|
||||
#define _REGISTERS_H_
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
VOID EmulatorSetStack(WORD Segment, DWORD Offset);
|
||||
|
||||
#if 0 // Those function prototypes are already included via ddk/vddsvc.h
|
||||
|
||||
PVOID WINAPI getIntelRegistersPointer(VOID);
|
||||
|
||||
ULONG WINAPI getEAX(VOID);
|
||||
VOID WINAPI setEAX(ULONG);
|
||||
USHORT WINAPI getAX(VOID);
|
||||
VOID WINAPI setAX(USHORT);
|
||||
UCHAR WINAPI getAH(VOID);
|
||||
VOID WINAPI setAH(UCHAR);
|
||||
UCHAR WINAPI getAL(VOID);
|
||||
VOID WINAPI setAL(UCHAR);
|
||||
|
||||
ULONG WINAPI getEBX(VOID);
|
||||
VOID WINAPI setEBX(ULONG);
|
||||
USHORT WINAPI getBX(VOID);
|
||||
VOID WINAPI setBX(USHORT);
|
||||
UCHAR WINAPI getBH(VOID);
|
||||
VOID WINAPI setBH(UCHAR);
|
||||
UCHAR WINAPI getBL(VOID);
|
||||
VOID WINAPI setBL(UCHAR);
|
||||
|
||||
ULONG WINAPI getECX(VOID);
|
||||
VOID WINAPI setECX(ULONG);
|
||||
USHORT WINAPI getCX(VOID);
|
||||
VOID WINAPI setCX(USHORT);
|
||||
UCHAR WINAPI getCH(VOID);
|
||||
VOID WINAPI setCH(UCHAR);
|
||||
UCHAR WINAPI getCL(VOID);
|
||||
VOID WINAPI setCL(UCHAR);
|
||||
|
||||
ULONG WINAPI getEDX(VOID);
|
||||
VOID WINAPI setEDX(ULONG);
|
||||
USHORT WINAPI getDX(VOID);
|
||||
VOID WINAPI setDX(USHORT);
|
||||
UCHAR WINAPI getDH(VOID);
|
||||
VOID WINAPI setDH(UCHAR);
|
||||
UCHAR WINAPI getDL(VOID);
|
||||
VOID WINAPI setDL(UCHAR);
|
||||
|
||||
|
||||
|
||||
ULONG WINAPI getESP(VOID);
|
||||
VOID WINAPI setESP(ULONG);
|
||||
USHORT WINAPI getSP(VOID);
|
||||
VOID WINAPI setSP(USHORT);
|
||||
|
||||
ULONG WINAPI getEBP(VOID);
|
||||
VOID WINAPI setEBP(ULONG);
|
||||
USHORT WINAPI getBP(VOID);
|
||||
VOID WINAPI setBP(USHORT);
|
||||
|
||||
ULONG WINAPI getESI(VOID);
|
||||
VOID WINAPI setESI(ULONG);
|
||||
USHORT WINAPI getSI(VOID);
|
||||
VOID WINAPI setSI(USHORT);
|
||||
|
||||
ULONG WINAPI getEDI(VOID);
|
||||
VOID WINAPI setEDI(ULONG);
|
||||
USHORT WINAPI getDI(VOID);
|
||||
VOID WINAPI setDI(USHORT);
|
||||
|
||||
ULONG WINAPI getEIP(VOID);
|
||||
VOID WINAPI setEIP(ULONG);
|
||||
USHORT WINAPI getIP(VOID);
|
||||
VOID WINAPI setIP(USHORT);
|
||||
|
||||
USHORT WINAPI getCS(VOID);
|
||||
VOID WINAPI setCS(USHORT);
|
||||
USHORT WINAPI getSS(VOID);
|
||||
VOID WINAPI setSS(USHORT);
|
||||
USHORT WINAPI getDS(VOID);
|
||||
VOID WINAPI setDS(USHORT);
|
||||
USHORT WINAPI getES(VOID);
|
||||
VOID WINAPI setES(USHORT);
|
||||
USHORT WINAPI getFS(VOID);
|
||||
VOID WINAPI setFS(USHORT);
|
||||
USHORT WINAPI getGS(VOID);
|
||||
VOID WINAPI setGS(USHORT);
|
||||
|
||||
ULONG WINAPI getCF(VOID);
|
||||
VOID WINAPI setCF(ULONG);
|
||||
ULONG WINAPI getPF(VOID);
|
||||
VOID WINAPI setPF(ULONG);
|
||||
ULONG WINAPI getAF(VOID);
|
||||
VOID WINAPI setAF(ULONG);
|
||||
ULONG WINAPI getZF(VOID);
|
||||
VOID WINAPI setZF(ULONG);
|
||||
ULONG WINAPI getSF(VOID);
|
||||
VOID WINAPI setSF(ULONG);
|
||||
ULONG WINAPI getIF(VOID);
|
||||
VOID WINAPI setIF(ULONG);
|
||||
ULONG WINAPI getDF(VOID);
|
||||
VOID WINAPI setDF(ULONG);
|
||||
ULONG WINAPI getOF(VOID);
|
||||
VOID WINAPI setOF(ULONG);
|
||||
|
||||
ULONG WINAPI getEFLAGS(VOID);
|
||||
VOID WINAPI setEFLAGS(ULONG);
|
||||
|
||||
USHORT WINAPI getMSW(VOID);
|
||||
VOID WINAPI setMSW(USHORT);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _REGISTERS_H_
|
||||
|
||||
/* EOF */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user