- Continue to work on VGA attach/detach from console;
- Stick more #if(n)def STANDALONE to portions of code that are useful (or not) in standalone (i.e. not in OS-integrated) mode;
- Isolate the Dos***File functions in a new source file;
- Get rid of STACK_COUNTER, STACK_VAR_A and STACK_VAR_B since we now use 32-->16 bit callbacks (and therefore adjust the callback/INT32 trampoline stubs accordingly).

svn path=/trunk/; revision=63238
This commit is contained in:
Hermès Bélusca-Maïto 2014-05-11 19:25:09 +00:00
parent 5c08d6b6c5
commit cdfa735cd1
17 changed files with 809 additions and 668 deletions

View file

@ -21,6 +21,7 @@ list(APPEND SOURCE
hardware/vga.c
dos/dos32krnl/bios.c
dos/dos32krnl/dos.c
dos/dos32krnl/dosfiles.c
dos/dem.c
bop.c
callback.c

View file

@ -91,22 +91,13 @@ static WORD BiosPeekCharacter(VOID)
else return 0xFFFF;
}
WORD BiosGetCharacter(VOID)
static 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;
}
/* Check if there is a key available, and if so, remove it from the queue */
if (BiosKbdBufferTop(&CharacterData)) BiosKbdBufferPop();
else CharacterData = 0xFFFF;
return CharacterData;
}
@ -121,7 +112,17 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
{
/* Read the character (and wait if necessary) */
setAX(BiosGetCharacter());
WORD Character = BiosGetCharacter();
if (Character == 0xFFFF)
{
/* No key available. Set the handler CF to repeat the BOP */
setCF(1);
break;
}
setAX(Character);
break;
}
@ -130,13 +131,13 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
/* Get extended keystroke status */
case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
{
WORD Data = BiosPeekCharacter();
WORD Character = BiosPeekCharacter();
if (Data != 0xFFFF)
if (Character != 0xFFFF)
{
/* There is a character, clear ZF and return it */
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
setAX(Data);
setAX(Character);
}
else
{

View file

@ -21,8 +21,6 @@
/* FUNCTIONS ******************************************************************/
WORD BiosGetCharacter(VOID);
BOOLEAN KbdBiosInitialize(VOID);
VOID KbdBiosCleanup(VOID);

View file

@ -1532,6 +1532,37 @@ VOID WINAPI VidBiosVideoService(LPWORD Stack)
}
}
/*
* Those attach / detach functions are work-in-progress
*/
static BOOL Attached = TRUE;
VOID VidBiosAttachToConsole(VOID)
{
// VgaRefreshDisplay();
if (!Attached)
{
VgaAttachToConsole();
Attached = TRUE;
}
VgaRefreshDisplay();
VidBiosSyncCursorPosition();
}
VOID VidBiosDetachFromConsole(VOID)
{
/* Perform another screen refresh */
VgaRefreshDisplay();
/* Detach from the console */
VgaDetachFromConsole(FALSE);
Attached = FALSE;
}
BOOLEAN VidBiosInitialize(VOID)
{
/* Some interrupts are in fact addresses to tables */
@ -1541,6 +1572,15 @@ BOOLEAN VidBiosInitialize(VOID)
((PULONG)BaseAddress)[0x43] = (ULONG)NULL;
((PULONG)BaseAddress)[0x44] = (ULONG)NULL;
//
// FIXME: At the moment we always set a VGA mode. In the future,
// we should set this mode **only** when:
// - an app starts to use directly the video memory
// (that should be done in emulator.c)
// - or starts to use non-stream I/O interrupts
// (that should be done here, or maybe in VGA ??)
//
/* Set the default video mode */
VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);

View file

@ -37,9 +37,12 @@ enum
/* FUNCTIONS ******************************************************************/
VOID VidBiosSyncCursorPosition(VOID);
VOID WINAPI VidBiosVideoService(LPWORD Stack);
VOID VidBiosSyncCursorPosition(VOID);
VOID VidBiosDetachFromConsole(VOID);
VOID VidBiosAttachToConsole(VOID);
BOOLEAN VidBiosInitialize(VOID);
VOID VidBiosCleanup(VOID);

View file

@ -44,6 +44,13 @@ do { \
#define CALL16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
#define INT16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
//
// WARNING WARNING!!
//
// If you modify the code stubs here, think also
// about updating them in int32.c too!!
//
/* 16-bit generic interrupt code for calling a 32-bit interrupt handler */
BYTE Int16To32[] =
{
@ -52,12 +59,6 @@ BYTE Int16To32[] =
/* 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
@ -74,7 +75,8 @@ BYTE Int16To32[] =
0xEB, 0xF5, // jmp BOP_SEQ (offset -11)
// EXIT:
0x83, 0xC4, 0x08, // add sp, 8
// 0x44, 0x44, // inc sp, inc sp
0x83, 0xC4, 0x02, // add sp, 2
0xCF, // iret
};

View file

@ -21,7 +21,6 @@
#include "bop.h"
#include "bios/bios.h"
#include "hardware/vga.h"
/* Extra PSDK/NDK Headers */
#include <ndk/obtypes.h>
@ -138,8 +137,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
StartupInfo.cb = sizeof(StartupInfo);
VgaRefreshDisplay();
VgaDetachFromConsole(FALSE);
VidBiosDetachFromConsole();
Result = CreateProcessA(NULL,
CommandLine,
@ -171,9 +169,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
dwExitCode = GetLastError();
}
VgaAttachToConsole();
VgaRefreshDisplay();
VidBiosSyncCursorPosition();
VidBiosAttachToConsole();
setAL((UCHAR)dwExitCode);

View file

@ -24,65 +24,15 @@
/* 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 DosReadCharacter(WORD FileHandle)
{
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);
}
/* Use the file reading function */
DosReadFile(FileHandle, &Character, 1, &BytesRead);
return Character;
}
@ -117,12 +67,12 @@ BOOLEAN DosCheckInput(VOID)
}
}
VOID DosPrintCharacter(CHAR Character)
VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
{
WORD BytesWritten;
/* Use the file writing function */
DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten);
DosWriteFile(FileHandle, &Character, 1, &BytesWritten);
}
BOOLEAN DosBIOSInitialize(VOID)

View file

@ -1,7 +1,7 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos.c
* FILE: dos/dos32krnl/dos.c
* PURPOSE: VDM DOS Kernel
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
@ -29,8 +29,13 @@ static DWORD DiskTransferArea;
/*static*/ BYTE CurrentDrive;
static CHAR LastDrive = 'E';
static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
static HANDLE DosSystemFileTable[DOS_SFT_SIZE];
static WORD DosSftRefCount[DOS_SFT_SIZE];
static struct
{
HANDLE Handle;
WORD RefCount;
} DosSystemFileTable[DOS_SFT_SIZE];
static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
static BOOLEAN DosUmbLinked = FALSE;
static WORD DosErrorLevel = 0x0000;
@ -431,6 +436,11 @@ static WORD DosCopyEnvironmentBlock(LPCVOID Environment, LPCSTR ProgramName)
return DestSegment;
}
/* Taken from base/shell/cmd/console.c */
BOOL IsConsoleHandle(HANDLE hHandle)
{
@ -455,7 +465,7 @@ BOOL IsConsoleHandle(HANDLE hHandle)
return GetConsoleMode(hHandle, &dwMode);
}
static WORD DosOpenHandle(HANDLE Handle)
WORD DosOpenHandle(HANDLE Handle)
{
BYTE i;
WORD DosHandle;
@ -482,10 +492,10 @@ static WORD DosOpenHandle(HANDLE Handle)
for (i = 0; i < DOS_SFT_SIZE; i++)
{
/* Check if this is the same handle */
if (DosSystemFileTable[i] != Handle) continue;
if (DosSystemFileTable[i].Handle != Handle) continue;
/* Already in the table, reference it */
DosSftRefCount[i]++;
DosSystemFileTable[i].RefCount++;
/* Set the JFT entry to that SFT index */
HandleTable[DosHandle] = i;
@ -498,11 +508,11 @@ static WORD DosOpenHandle(HANDLE Handle)
for (i = 0; i < DOS_SFT_SIZE; i++)
{
/* Make sure this is an empty table entry */
if (DosSystemFileTable[i] != INVALID_HANDLE_VALUE) continue;
if (DosSystemFileTable[i].Handle != INVALID_HANDLE_VALUE) continue;
/* Initialize the empty table entry */
DosSystemFileTable[i] = Handle;
DosSftRefCount[i] = 1;
DosSystemFileTable[i].Handle = Handle;
DosSystemFileTable[i].RefCount = 1;
/* Set the JFT entry to that SFT index */
HandleTable[DosHandle] = i;
@ -531,7 +541,7 @@ HANDLE DosGetRealHandle(WORD DosHandle)
if (HandleTable[DosHandle] == 0xFF) return INVALID_HANDLE_VALUE;
/* Return the Win32 handle */
return DosSystemFileTable[HandleTable[DosHandle]];
return DosSystemFileTable[HandleTable[DosHandle]].Handle;
}
static VOID DosCopyHandleTable(LPBYTE DestinationTable)
@ -553,7 +563,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
DestinationTable[i] = (BYTE)i;
/* Increase the reference count */
DosSftRefCount[i]++;
DosSystemFileTable[i].RefCount++;
}
/* Done */
@ -570,7 +580,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
DestinationTable[i] = SourceTable[i];
/* Increase the reference count */
DosSftRefCount[SourceTable[i]]++;
DosSystemFileTable[SourceTable[i]].RefCount++;
}
}
@ -594,16 +604,16 @@ static BOOLEAN DosCloseHandle(WORD DosHandle)
/* Decrement the reference count of the SFT entry */
SftIndex = HandleTable[DosHandle];
DosSftRefCount[SftIndex]--;
DosSystemFileTable[SftIndex].RefCount--;
/* Check if the reference count fell to zero */
if (!DosSftRefCount[SftIndex])
if (!DosSystemFileTable[SftIndex].RefCount)
{
/* Close the file, it's no longer needed */
CloseHandle(DosSystemFileTable[SftIndex]);
CloseHandle(DosSystemFileTable[SftIndex].Handle);
/* Clear the handle */
DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE;
DosSystemFileTable[SftIndex].Handle = INVALID_HANDLE_VALUE;
}
/* Clear the entry in the JFT */
@ -641,7 +651,7 @@ static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
/* Increment the reference count of the SFT entry */
SftIndex = HandleTable[OldHandle];
DosSftRefCount[SftIndex]++;
DosSystemFileTable[SftIndex].RefCount++;
/* Make the new handle point to that SFT entry */
HandleTable[NewHandle] = SftIndex;
@ -650,260 +660,11 @@ static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
return TRUE;
}
static WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
{
HANDLE FileHandle;
WORD DosHandle;
DPRINT("DosCreateFile: FilePath \"%s\", Attributes 0x%04X\n",
FilePath,
Attributes);
/* Create the file */
FileHandle = CreateFileA(FilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
Attributes,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
static WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
{
HANDLE FileHandle;
ACCESS_MASK Access = 0;
WORD DosHandle;
DPRINT("DosOpenFile: FilePath \"%s\", AccessMode 0x%04X\n",
FilePath,
AccessMode);
/* Parse the access mode */
switch (AccessMode & 3)
{
case 0:
{
/* Read-only */
Access = GENERIC_READ;
break;
}
case 1:
{
/* Write only */
Access = GENERIC_WRITE;
break;
}
case 2:
{
/* Read and write */
Access = GENERIC_READ | GENERIC_WRITE;
break;
}
default:
{
/* Invalid */
return ERROR_INVALID_PARAMETER;
}
}
/* Open the file */
FileHandle = CreateFileA(FilePath,
Access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesRead32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT("DosReadFile: FileHandle 0x%04X, Count 0x%04X\n", FileHandle, Count);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
/* Read the file */
if (!ReadFile(Handle, Buffer, Count, &BytesRead32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
/* The number of bytes read is always 16-bit */
*BytesRead = LOWORD(BytesRead32);
/* Return the error code */
return Result;
}
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++)
{
/* Save AX and BX */
USHORT AX = getAX();
USHORT BX = getBX();
/* Set the parameters */
setAL(((PCHAR)Buffer)[i]);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
/* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
setAH(0x0E);
Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
/* Restore AX and BX */
setBX(BX);
setAX(AX);
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;
}
static WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
{
WORD Result = ERROR_SUCCESS;
DWORD FilePointer;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
FileHandle,
Offset,
Origin);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
/* Check if the origin is valid */
if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
{
return ERROR_INVALID_FUNCTION;
}
/* Move the file pointer */
FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
/* Check if there's a possibility the operation failed */
if (FilePointer == INVALID_SET_FILE_POINTER)
{
/* Get the real error code */
Result = (WORD)GetLastError();
}
if (Result != ERROR_SUCCESS)
{
/* The operation did fail */
return Result;
}
/* Return the file pointer, if requested */
if (NewOffset) *NewOffset = FilePointer;
/* Return success */
return ERROR_SUCCESS;
}
static BOOLEAN DosFlushFileBuffers(WORD FileHandle)
{
HANDLE Handle = DosGetRealHandle(FileHandle);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return FALSE;
/*
* No need to check whether the handle is a console handle since
* FlushFileBuffers() automatically does this check and calls
* FlushConsoleInputBuffer() for us.
*/
// if (IsConsoleHandle(Handle))
// return (BOOLEAN)FlushConsoleInputBuffer(Handle);
// else
return (BOOLEAN)FlushFileBuffers(Handle);
}
static BOOLEAN DosChangeDrive(BYTE Drive)
{
@ -1279,6 +1040,36 @@ Cleanup:
return Result;
}
DWORD DosStartProcess(IN LPCSTR ExecutablePath,
IN LPCSTR CommandLine,
IN PVOID Environment)
{
DWORD Result;
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
ExecutablePath,
CommandLine,
Environment,
NULL,
NULL);
if (Result != ERROR_SUCCESS) goto Quit;
/* Attach to the console */
VidBiosAttachToConsole(); // FIXME: And in fact, attach the full NTVDM UI to the console
/* Start simulation */
SetEvent(VdmTaskEvent);
EmulatorSimulate();
/* Detach from the console */
VidBiosDetachFromConsole(); // FIXME: And in fact, detach the full NTVDM UI from the console
Quit:
return Result;
}
#ifndef STANDALONE
WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
LPCSTR ProgramName,
PDOS_EXEC_PARAM_BLOCK Parameters)
@ -1363,16 +1154,17 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
GetNextVDMCommand(&CommandInfo);
/* Load the executable */
Result= DosLoadExecutable(LoadType,
AppName,
CmdLine,
Env,
&Parameters->StackLocation,
&Parameters->EntryPoint);
Result = DosLoadExecutable(LoadType,
AppName,
CmdLine,
Env,
&Parameters->StackLocation,
&Parameters->EntryPoint);
if (Result != ERROR_SUCCESS)
{
DisplayMessage(L"Could not load '%S'. Error: %u", AppName, Result);
break;
// FIXME: Decrement the reenter count. Or, instead, just increment
// the VDM reenter count *only* if this call succeeds...
}
break;
@ -1392,6 +1184,7 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
return ERROR_SUCCESS;
}
#endif
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
{
@ -1400,7 +1193,6 @@ VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
PDOS_MCB CurrentMcb;
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
VDM_COMMAND_INFO CommandInfo;
DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n",
Psp,
@ -1451,10 +1243,13 @@ Done:
}
}
#ifndef STANDALONE
// FIXME: This is probably not the best way to do it
/* Check if this was a nested DOS task */
if (CurrentPsp != SYSTEM_PSP)
{
VDM_COMMAND_INFO CommandInfo;
/* Decrement the re-entry count */
CommandInfo.TaskId = SessionId;
CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
@ -1468,6 +1263,7 @@ Done:
CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
GetNextVDMCommand(&CommandInfo);
}
#endif
/* Save the return code - Normal termination */
DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
@ -1500,12 +1296,12 @@ BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
* for a list of possible flags.
*/
if (Handle == DosSystemFileTable[0])
if (Handle == DosSystemFileTable[DOS_INPUT_HANDLE].Handle)
{
/* Console input */
InfoWord |= 1 << 0;
}
else if (Handle == DosSystemFileTable[1])
else if (Handle == DosSystemFileTable[DOS_OUTPUT_HANDLE].Handle)
{
/* Console output */
InfoWord |= 1 << 1;
@ -1556,11 +1352,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Read Character from STDIN with Echo */
case 0x01:
{
Character = DosReadCharacter();
DosPrintCharacter(Character);
// FIXME: Under DOS 2+, input / output handle may be redirected!!!!
Character = DosReadCharacter(DOS_INPUT_HANDLE);
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
/* Let the BOP repeat if needed */
if (getCF()) break;
// /* Let the BOP repeat if needed */
// if (getCF()) break;
setAL(Character);
break;
@ -1569,8 +1366,9 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Write Character to STDOUT */
case 0x02:
{
// FIXME: Under DOS 2+, output handle may be redirected!!!!
Character = getDL();
DosPrintCharacter(Character);
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
/*
* We return the output character (DOS 2.1+).
@ -1588,7 +1386,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
{
// FIXME: Really read it from STDAUX!
DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
setAL(DosReadCharacter());
// setAL(DosReadCharacter());
break;
}
@ -1597,7 +1395,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
{
// FIXME: Really write it to STDAUX!
DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
DosPrintCharacter(getDL());
// DosPrintCharacter(getDL());
break;
}
@ -1616,10 +1414,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
{
Character = getDL();
// FIXME: Under DOS 2+, output handle may be redirected!!!!
if (Character != 0xFF)
{
/* Output */
DosPrintCharacter(Character);
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
/*
* We return the output character (DOS 2.1+).
@ -1634,7 +1434,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
if (DosCheckInput())
{
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
setAL(DosReadCharacter());
setAL(DosReadCharacter(DOS_INPUT_HANDLE));
}
else
{
@ -1651,10 +1451,15 @@ VOID WINAPI DosInt21h(LPWORD Stack)
case 0x07:
case 0x08:
{
Character = DosReadCharacter();
// FIXME: Under DOS 2+, input handle may be redirected!!!!
Character = DosReadCharacter(DOS_INPUT_HANDLE);
/* Let the BOP repeat if needed */
if (getCF()) break;
// FIXME: For 0x07, do not check Ctrl-C/Break.
// For 0x08, do check those control sequences and if needed,
// call INT 0x23.
// /* Let the BOP repeat if needed */
// if (getCF()) break;
setAL(Character);
break;
@ -1667,7 +1472,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
while (*String != '$')
{
DosPrintCharacter(*String);
DosPrintCharacter(DOS_OUTPUT_HANDLE, *String);
String++;
}
@ -1683,26 +1488,27 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Read Buffered Input */
case 0x0A:
{
WORD Count = 0;
InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
while (Stack[STACK_COUNTER] < InputBuffer->MaxLength)
{
/* Try to read a character */
Character = DosReadCharacter();
DPRINT1("Read Buffered Input\n");
/* If it's not ready yet, let the BOP repeat */
if (getCF()) break;
while (Count < InputBuffer->MaxLength)
{
/* Try to read a character (wait) */
Character = DosReadCharacter(DOS_INPUT_HANDLE);
/* Echo the character and append it to the buffer */
DosPrintCharacter(Character);
InputBuffer->Buffer[Stack[STACK_COUNTER]] = Character;
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
InputBuffer->Buffer[Count] = Character;
if (Character == '\r') break;
Stack[STACK_COUNTER]++;
Count++;
}
/* Update the length */
InputBuffer->Length = Stack[STACK_COUNTER];
InputBuffer->Length = Count;
break;
}
@ -1719,7 +1525,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
BYTE InputFunction = getAL();
/* Flush STDIN buffer */
DosFlushFileBuffers(DOS_INPUT_HANDLE); // Maybe just create a DosFlushInputBuffer...
DosFlushFileBuffers(DOS_INPUT_HANDLE);
/*
* If the input function number contained in AL is valid, i.e.
@ -2163,47 +1969,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
/* Read from File or Device */
case 0x3F:
{
WORD Handle = getBX();
LPBYTE Buffer = (LPBYTE)SEG_OFF_TO_PTR(getDS(), getDX());
WORD Count = getCX();
WORD BytesRead = 0;
WORD ErrorCode = ERROR_SUCCESS;
CHAR Character;
if (IsConsoleHandle(DosGetRealHandle(Handle)))
{
while (Stack[STACK_COUNTER] < Count)
{
/* Read a character from the BIOS */
Character = LOBYTE(BiosGetCharacter());
/* Stop if the BOP needs to be repeated */
if (getCF()) break;
// FIXME: Security checks!
DosPrintCharacter(Character);
Buffer[Stack[STACK_COUNTER]++] = Character;
if (Character == '\r')
{
/* Stop on first carriage return */
DosPrintCharacter('\n');
break;
}
}
if (Character != '\r')
{
if (Stack[STACK_COUNTER] < Count) ErrorCode = ERROR_NOT_READY;
else BytesRead = Count;
}
else BytesRead = Stack[STACK_COUNTER];
}
else
{
/* Use the file reading function */
ErrorCode = DosReadFile(Handle, Buffer, Count, &BytesRead);
}
WORD ErrorCode = DosReadFile(getBX(),
SEG_OFF_TO_PTR(getDS(), getDX()),
getCX(),
&BytesRead);
if (ErrorCode == ERROR_SUCCESS)
{
@ -2215,6 +1985,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
setAX(ErrorCode);
}
break;
}
@ -2358,7 +2129,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
WORD NewHandle;
HANDLE Handle = DosGetRealHandle(getBX());
if (Handle != INVALID_HANDLE_VALUE)
if (Handle == INVALID_HANDLE_VALUE)
{
/* The handle is invalid */
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
@ -2491,6 +2262,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
break;
}
#ifndef STANDALONE
/* Execute */
case 0x4B:
{
@ -2511,6 +2283,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
break;
}
#endif
/* Terminate With Return Code */
case 0x4C:
@ -2540,8 +2313,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
getCX());
setAX(Result);
if (Result == ERROR_SUCCESS) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
if (Result == ERROR_SUCCESS)
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break;
}
@ -2552,8 +2328,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea));
setAX(Result);
if (Result == ERROR_SUCCESS) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
if (Result == ERROR_SUCCESS)
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
else
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
break;
}
@ -2581,6 +2360,23 @@ VOID WINAPI DosInt21h(LPWORD Stack)
break;
}
/* Internal - Get "List of lists" (SYSVARS) */
case 0x52:
{
/*
* On return, ES points at the DOS data segment (see also INT 2F/AX=1203h).
* See Ralf Brown: http://www.ctyme.com/intr/rb-2983.htm
* for more information.
*/
/* Return the DOS "list of lists" in ES:BX */
setES(0x0000);
setBX(0x0000);
DisplayMessage(L"Required for AARD code, do you remember? :P");
break;
}
/* Get/Set Memory Management Options */
case 0x58:
{
@ -2666,32 +2462,6 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
* for more information.
*/
#if 0
if (Stack[STACK_COUNTER] == 0)
{
Stack[STACK_COUNTER]++;
/* Save AX and BX */
Stack[STACK_VAR_A] = getAX();
Stack[STACK_VAR_B] = getBX();
/* Rewind the BOP manually, we can't use CF because the interrupt could modify it */
EmulatorExecute(getCS(), getIP() - 4);
/* Call INT 0x10, AH = 0x0E */
setAH(0x0E);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
EmulatorInterrupt(0x10);
}
else
{
/* Restore AX and BX */
setAX(Stack[STACK_VAR_A]);
setBX(Stack[STACK_VAR_B]);
}
#else
/* Save AX and BX */
USHORT AX = getAX();
USHORT BX = getBX();
@ -2707,12 +2477,11 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
/* Restore AX and BX */
setBX(BX);
setAX(AX);
#endif
}
VOID WINAPI DosInt2Fh(LPWORD Stack)
{
DPRINT1("DOS System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
DPRINT1("DOS Internal System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
getAH(), getAL());
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
}
@ -2778,17 +2547,19 @@ BOOLEAN DosKRNLInitialize(VOID)
/* Initialize the SFT */
for (i = 0; i < DOS_SFT_SIZE; i++)
{
DosSystemFileTable[i] = INVALID_HANDLE_VALUE;
DosSftRefCount[i] = 0;
DosSystemFileTable[i].Handle = INVALID_HANDLE_VALUE;
DosSystemFileTable[i].RefCount = 0;
}
/* Get handles to standard I/O devices */
DosSystemFileTable[0] = GetStdHandle(STD_INPUT_HANDLE);
DosSystemFileTable[1] = GetStdHandle(STD_OUTPUT_HANDLE);
DosSystemFileTable[2] = GetStdHandle(STD_ERROR_HANDLE);
DosSystemFileTable[0].Handle = GetStdHandle(STD_INPUT_HANDLE);
DosSystemFileTable[1].Handle = GetStdHandle(STD_OUTPUT_HANDLE);
DosSystemFileTable[2].Handle = GetStdHandle(STD_ERROR_HANDLE);
/* Initialize the reference counts */
DosSftRefCount[0] = DosSftRefCount[1] = DosSftRefCount[2] = 1;
DosSystemFileTable[0].RefCount =
DosSystemFileTable[1].RefCount =
DosSystemFileTable[2].RefCount = 1;
#endif

View file

@ -30,10 +30,12 @@
#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 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)))
@ -172,9 +174,9 @@ do { \
* DOS BIOS Functions
* See bios.c
*/
CHAR DosReadCharacter(VOID);
CHAR DosReadCharacter(WORD FileHandle);
BOOLEAN DosCheckInput(VOID);
VOID DosPrintCharacter(CHAR Character);
VOID DosPrintCharacter(WORD FileHandle, CHAR Character);
BOOLEAN DosBIOSInitialize(VOID);
@ -184,9 +186,15 @@ BOOLEAN DosBIOSInitialize(VOID);
* See dos.c
*/
BOOL IsConsoleHandle(HANDLE hHandle);
WORD DosOpenHandle(HANDLE Handle);
HANDLE DosGetRealHandle(WORD DosHandle);
WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes);
WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode);
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead);
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset);
BOOL DosFlushFileBuffers(WORD FileHandle);
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment);
DWORD DosLoadExecutable(
@ -202,6 +210,9 @@ WORD DosCreateProcess(
LPCSTR ProgramName,
PDOS_EXEC_PARAM_BLOCK Parameters
);
DWORD DosStartProcess(IN LPCSTR ExecutablePath,
IN LPCSTR CommandLine,
IN PVOID Environment);
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);

View file

@ -0,0 +1,331 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: dos/dos32krnl/dosfiles.c
* PURPOSE: DOS Files
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
// #include "callback.h"
#include "dos.h"
#include "dos/dem.h"
#include "bios/bios.h"
/* PRIVATE VARIABLES **********************************************************/
/* PUBLIC FUNCTIONS ***********************************************************/
WORD DosCreateFile(LPWORD Handle, LPCSTR FilePath, WORD Attributes)
{
HANDLE FileHandle;
WORD DosHandle;
DPRINT("DosCreateFile: FilePath \"%s\", Attributes 0x%04X\n",
FilePath,
Attributes);
/* Create the file */
FileHandle = CreateFileA(FilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
Attributes,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
WORD DosOpenFile(LPWORD Handle, LPCSTR FilePath, BYTE AccessMode)
{
HANDLE FileHandle;
ACCESS_MASK Access = 0;
WORD DosHandle;
DPRINT("DosOpenFile: FilePath \"%s\", AccessMode 0x%04X\n",
FilePath,
AccessMode);
/* Parse the access mode */
switch (AccessMode & 3)
{
case 0:
{
/* Read-only */
Access = GENERIC_READ;
break;
}
case 1:
{
/* Write only */
Access = GENERIC_WRITE;
break;
}
case 2:
{
/* Read and write */
Access = GENERIC_READ | GENERIC_WRITE;
break;
}
default:
{
/* Invalid */
return ERROR_INVALID_PARAMETER;
}
}
/* Open the file */
FileHandle = CreateFileA(FilePath,
Access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
/* Return the error code */
return (WORD)GetLastError();
}
/* Open the DOS handle */
DosHandle = DosOpenHandle(FileHandle);
if (DosHandle == INVALID_DOS_HANDLE)
{
/* Close the handle */
CloseHandle(FileHandle);
/* Return the error code */
return ERROR_TOO_MANY_OPEN_FILES;
}
/* It was successful */
*Handle = DosHandle;
return ERROR_SUCCESS;
}
WORD DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesRead32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT1("DosReadFile: 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))
{
CHAR Character;
/*
* Use BIOS Get Keystroke function
*/
/* Save AX */
USHORT AX = getAX();
for (BytesRead32 = 0; BytesRead32 < Count; BytesRead32++)
{
/* Call the BIOS INT 16h, AH=00h "Get Keystroke" */
setAH(0x00);
Int32Call(&DosContext, BIOS_KBD_INTERRUPT);
/* Retrieve the character in AL (scan code is in AH) */
Character = getAL();
// FIXME: Sometimes we need echo, some other times not.
// DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
((PCHAR)Buffer)[BytesRead32] = Character;
/* Stop on first carriage return */
if (Character == '\r')
{
// DosPrintCharacter(DOS_OUTPUT_HANDLE, '\n');
break;
}
// BytesRead32++;
}
/* Restore AX */
setAX(AX);
}
else
{
/* Read the file */
if (!ReadFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &BytesRead32, NULL))
{
/* Store the error code */
Result = (WORD)GetLastError();
}
}
/* The number of bytes read is always 16-bit */
*BytesRead = LOWORD(BytesRead32);
/* Return the error code */
return Result;
}
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten)
{
WORD Result = ERROR_SUCCESS;
DWORD BytesWritten32 = 0;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT1("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))
{
/*
* Use BIOS Teletype function
*/
/* Save AX and BX */
USHORT AX = getAX();
USHORT BX = getBX();
// FIXME: Use BIOS Write String function INT 10h, AH=13h ??
for (BytesWritten32 = 0; BytesWritten32 < Count; BytesWritten32++)
{
/* Set the parameters */
setAL(((PCHAR)Buffer)[BytesWritten32]);
setBL(DOS_CHAR_ATTRIBUTE);
setBH(Bda->VideoPage);
/* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */
setAH(0x0E);
Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT);
// BytesWritten32++;
}
/* Restore AX and BX */
setBX(BX);
setAX(AX);
}
else
{
/* Write the file */
if (!WriteFile(Handle, Buffer, Count /* * sizeof(CHAR) */, &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;
}
WORD DosSeekFile(WORD FileHandle, LONG Offset, BYTE Origin, LPDWORD NewOffset)
{
WORD Result = ERROR_SUCCESS;
DWORD FilePointer;
HANDLE Handle = DosGetRealHandle(FileHandle);
DPRINT("DosSeekFile: FileHandle 0x%04X, Offset 0x%08X, Origin 0x%02X\n",
FileHandle,
Offset,
Origin);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return ERROR_INVALID_HANDLE;
/* Check if the origin is valid */
if (Origin != FILE_BEGIN && Origin != FILE_CURRENT && Origin != FILE_END)
{
return ERROR_INVALID_FUNCTION;
}
/* Move the file pointer */
if (IsConsoleHandle(Handle))
{
/* Always succeeds when seeking a console handle */
FilePointer = 0;
Result = ERROR_SUCCESS;
}
else
{
FilePointer = SetFilePointer(Handle, Offset, NULL, Origin);
}
/* Check if there's a possibility the operation failed */
if (FilePointer == INVALID_SET_FILE_POINTER)
{
/* Get the real error code */
Result = (WORD)GetLastError();
}
if (Result != ERROR_SUCCESS)
{
/* The operation did fail */
return Result;
}
/* Return the file pointer, if requested */
if (NewOffset) *NewOffset = FilePointer;
/* Return success */
return ERROR_SUCCESS;
}
// This function is almost exclusively used as a DosFlushInputBuffer
BOOL DosFlushFileBuffers(WORD FileHandle)
{
HANDLE Handle = DosGetRealHandle(FileHandle);
/* Make sure the handle is valid */
if (Handle == INVALID_HANDLE_VALUE) return FALSE;
/*
* No need to check whether the handle is a console handle since
* FlushFileBuffers() automatically does this check and calls
* FlushConsoleInputBuffer() for us.
*/
return FlushFileBuffers(Handle);
}

View file

@ -395,13 +395,22 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
/* Initialize the PS2 port */
PS2Initialize(ConsoleInput);
/**************** ATTACH INPUT WITH CONSOLE *****************/
/* Start the input thread */
InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL);
// if (InputThread == NULL) return FALSE;
if (InputThread == NULL)
{
DisplayMessage(L"Failed to create the console input thread.");
return FALSE;
}
/************************************************************/
/* Initialize the VGA */
// if (!VgaInitialize(ConsoleOutput)) return FALSE;
VgaInitialize(ConsoleOutput);
if (!VgaInitialize(ConsoleOutput))
{
DisplayMessage(L"Failed to initialize VGA support.");
return FALSE;
}
/* Initialize the software callback system and register the emulator BOPs */
InitializeCallbacks();

View file

@ -34,13 +34,15 @@
#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
//
// WARNING WARNING!!
// If you're changing the indices here, you then need to
// also fix the BOP code in callback.c !!!!!!!!!!!!!!!!!
//
#define STACK_INT_NUM 0
#define STACK_IP 1
#define STACK_CS 2
#define STACK_FLAGS 3
/* Basic Memory Management */

View file

@ -421,7 +421,7 @@ static VOID VgaUpdateCursorPosition(VOID)
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
VidBiosSyncCursorPosition();
// VidBiosSyncCursorPosition();
VgaUpdateTextCursor();
}
@ -538,61 +538,6 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
return TRUE;
}
BOOL VgaAttachToConsole(VOID)
{
if (TextResolution.X == 0 || TextResolution.Y == 0)
DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
if (TextResolution.X == 0) TextResolution.X = 80;
if (TextResolution.Y == 0) TextResolution.Y = 25;
return VgaAttachToConsoleInternal(&TextResolution);
}
VOID VgaDetachFromConsole(BOOL ChangingMode)
{
ULONG dummyLength;
PVOID dummyPtr;
COORD dummySize = {0};
__RegisterConsoleVDM(0,
NULL,
NULL,
NULL,
0,
&dummyLength,
&dummyPtr,
NULL,
0,
dummySize,
(PCHAR*)&dummyPtr);
TextFramebuffer = NULL;
if (!ChangingMode)
{
SMALL_RECT ConRect;
/* Restore the old screen buffer */
SetConsoleActiveScreenBuffer(TextConsoleBuffer);
/* Restore the original console size */
ConRect.Left = 0;
ConRect.Top = 0;
ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
/*
* See the following trick explanation in VgaAttachToConsoleInternal.
*/
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
/* Restore the original cursor shape */
SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
}
}
static BOOL IsConsoleHandle(HANDLE hHandle)
{
DWORD dwMode;
@ -1038,7 +983,10 @@ static BOOL VgaEnterTextMode(PCOORD Resolution)
return FALSE;
}
}
else VgaUpdateCursorPosition();
else
{
VgaUpdateCursorPosition();
}
/* The active framebuffer is now the text framebuffer */
ConsoleFramebuffer = TextFramebuffer;
@ -1886,6 +1834,71 @@ VOID VgaResetPalette(VOID)
PaletteChanged = TRUE;
}
BOOL VgaAttachToConsole(VOID)
{
//
// FIXME: We should go back to the saved screen state
//
if (TextResolution.X == 0 || TextResolution.Y == 0)
DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
if (TextResolution.X == 0) TextResolution.X = 80;
if (TextResolution.Y == 0) TextResolution.Y = 25;
return VgaAttachToConsoleInternal(&TextResolution);
}
VOID VgaDetachFromConsole(BOOL ChangingMode)
{
ULONG dummyLength;
PVOID dummyPtr;
COORD dummySize = {0};
//
// FIXME: We should save the screen state
//
__RegisterConsoleVDM(0,
NULL,
NULL,
NULL,
0,
&dummyLength,
&dummyPtr,
NULL,
0,
dummySize,
(PCHAR*)&dummyPtr);
TextFramebuffer = NULL;
if (!ChangingMode)
{
SMALL_RECT ConRect;
/* Restore the old screen buffer */
SetConsoleActiveScreenBuffer(TextConsoleBuffer);
/* Restore the original console size */
ConRect.Left = 0;
ConRect.Top = 0;
ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
/*
* See the following trick explanation in VgaAttachToConsoleInternal.
*/
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
/* Restore the original cursor shape */
SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
}
}
BOOLEAN VgaInitialize(HANDLE TextHandle)
{
/* Save the default text-mode console output handle */

View file

@ -58,6 +58,13 @@ VOID WINAPI ControlBop(LPWORD Stack)
VOID InitializeInt32(WORD BiosSegment)
{
//
// WARNING WARNING!!
//
// If you modify the code stubs here, think also
// about updating them in callback.c too!!
//
LPDWORD IntVecTable = (LPDWORD)BaseAddress;
LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0);
USHORT i;
@ -74,15 +81,6 @@ VOID InitializeInt32(WORD BiosSegment)
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
@ -113,9 +111,11 @@ VOID InitializeInt32(WORD BiosSegment)
BiosCode[Offset++] = 0xF5;
// EXIT:
BiosCode[Offset++] = 0x83; // add sp, 8
// BiosCode[Offset++] = 0x44; // inc sp
// BiosCode[Offset++] = 0x44; // inc sp
BiosCode[Offset++] = 0x83; // add sp, 2
BiosCode[Offset++] = 0xC4;
BiosCode[Offset++] = 0x08;
BiosCode[Offset++] = 0x02;
BiosCode[Offset++] = 0xCF; // iret

View file

@ -21,12 +21,6 @@
#include "resource.h"
/*
* Activate this line if you want to run NTVDM in standalone mode with:
* ntvdm.exe <program>
*/
// #define STANDALONE
/* VARIABLES ******************************************************************/
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
@ -39,7 +33,10 @@ static HMENU hConsoleMenu = NULL;
static INT VdmMenuPos = -1;
static BOOLEAN ShowPointer = FALSE;
#ifndef STANDALONE
ULONG SessionId = 0;
#endif
HANDLE VdmTaskEvent = NULL;
/*
@ -124,7 +121,7 @@ AppendMenuItems(HMENU hMenu,
static VOID
CreateVdmMenu(HANDLE ConOutHandle)
{
hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
hConsoleMenu = ConsoleMenuControl(ConOutHandle,
ID_SHOWHIDE_MOUSE,
ID_VDM_QUIT);
if (hConsoleMenu == NULL) return;
@ -176,7 +173,8 @@ static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
/* PUBLIC FUNCTIONS ***********************************************************/
VOID DisplayMessage(LPCWSTR Format, ...)
VOID
DisplayMessage(LPCWSTR Format, ...)
{
WCHAR Buffer[256];
va_list Parameters;
@ -188,7 +186,9 @@ VOID DisplayMessage(LPCWSTR Format, ...)
va_end(Parameters);
}
BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
static BOOL
WINAPI
ConsoleCtrlHandler(DWORD ControlType)
{
switch (ControlType)
{
@ -224,12 +224,14 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
return TRUE;
}
VOID ConsoleInitUI(VOID)
static VOID
ConsoleInitUI(VOID)
{
CreateVdmMenu(ConsoleOutput);
}
VOID ConsoleCleanupUI(VOID)
static VOID
ConsoleCleanupUI(VOID)
{
/* Display again properly the mouse pointer */
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
@ -237,7 +239,97 @@ VOID ConsoleCleanupUI(VOID)
DestroyVdmMenu();
}
DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
static BOOL
ConsoleAttach(VOID)
{
/* 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;
}
static VOID
ConsoleDetach(VOID)
{
/* Restore the original input and output console modes */
SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
/* Cleanup the UI */
ConsoleCleanupUI();
}
static BOOL
ConsoleInit(VOID)
{
/* Set the handler routine */
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
/* Enable the CTRL_LAST_CLOSE_EVENT */
SetLastConsoleEventActive();
/*
* NOTE: The CONIN$ and CONOUT$ "virtual" files
* always point to non-redirected console handles.
*/
/* 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;
}
/* Effectively attach to the console */
return ConsoleAttach();
}
static VOID
ConsoleCleanup(VOID)
{
/* Detach from the console */
ConsoleDetach();
/* Close the console handles */
if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
}
DWORD
WINAPI
PumpConsoleInput(LPVOID Parameter)
{
HANDLE ConsoleInput = (HANDLE)Parameter;
INPUT_RECORD InputRecord;
@ -296,74 +388,10 @@ DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
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)
#ifndef STANDALONE
static DWORD
WINAPI
CommandThreadProc(LPVOID Parameter)
{
BOOLEAN First = TRUE;
DWORD Result;
@ -404,39 +432,25 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
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);
DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine);
Result = DosStartProcess(AppName, CmdLine, Env);
if (Result != ERROR_SUCCESS)
{
DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
break;
// break;
continue;
}
/* 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;
}
#endif
INT wmain(INT argc, WCHAR *argv[])
INT
wmain(INT argc, WCHAR *argv[])
{
#ifdef STANDALONE
@ -459,6 +473,7 @@ INT wmain(INT argc, WCHAR *argv[])
}
#else
INT i;
WCHAR *endptr;
@ -530,27 +545,16 @@ INT wmain(INT argc, WCHAR *argv[])
#else
/* Start the process from the command line */
DPRINT1("Starting '%s'...\n", ApplicationName);
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
ApplicationName,
CommandLine,
GetEnvironmentStrings(),
NULL,
NULL);
DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine);
Result = DosStartProcess(ApplicationName,
CommandLine,
GetEnvironmentStrings());
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:

View file

@ -28,13 +28,22 @@
#include <vddsvc.h>
DWORD WINAPI SetLastConsoleEventActive(VOID);
#include <debug.h>
DWORD WINAPI SetLastConsoleEventActive(VOID);
/*
* Activate this line if you want to run NTVDM in standalone mode with:
* ntvdm.exe <program>
*/
#define STANDALONE
/* FUNCTIONS ******************************************************************/
#ifndef STANDALONE
extern ULONG SessionId;
#endif
extern HANDLE VdmTaskEvent;
VOID DisplayMessage(LPCWSTR Format, ...);