mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 23:12:56 +00:00
[NTVDM]
- 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:
parent
5c08d6b6c5
commit
cdfa735cd1
17 changed files with 809 additions and 668 deletions
|
@ -21,6 +21,7 @@ list(APPEND SOURCE
|
||||||
hardware/vga.c
|
hardware/vga.c
|
||||||
dos/dos32krnl/bios.c
|
dos/dos32krnl/bios.c
|
||||||
dos/dos32krnl/dos.c
|
dos/dos32krnl/dos.c
|
||||||
|
dos/dos32krnl/dosfiles.c
|
||||||
dos/dem.c
|
dos/dem.c
|
||||||
bop.c
|
bop.c
|
||||||
callback.c
|
callback.c
|
||||||
|
|
|
@ -91,22 +91,13 @@ static WORD BiosPeekCharacter(VOID)
|
||||||
else return 0xFFFF;
|
else return 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
WORD BiosGetCharacter(VOID)
|
static WORD BiosGetCharacter(VOID)
|
||||||
{
|
{
|
||||||
WORD CharacterData = 0;
|
WORD CharacterData = 0;
|
||||||
|
|
||||||
/* Check if there is a key available */
|
/* Check if there is a key available, and if so, remove it from the queue */
|
||||||
if (BiosKbdBufferTop(&CharacterData))
|
if (BiosKbdBufferTop(&CharacterData)) BiosKbdBufferPop();
|
||||||
{
|
else CharacterData = 0xFFFF;
|
||||||
/* 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;
|
return CharacterData;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +112,17 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
|
||||||
case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
|
case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
|
||||||
{
|
{
|
||||||
/* Read the character (and wait if necessary) */
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,13 +131,13 @@ static VOID WINAPI BiosKeyboardService(LPWORD Stack)
|
||||||
/* Get extended keystroke status */
|
/* Get extended keystroke status */
|
||||||
case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
|
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 */
|
/* There is a character, clear ZF and return it */
|
||||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
|
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
|
||||||
setAX(Data);
|
setAX(Character);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
WORD BiosGetCharacter(VOID);
|
|
||||||
|
|
||||||
BOOLEAN KbdBiosInitialize(VOID);
|
BOOLEAN KbdBiosInitialize(VOID);
|
||||||
VOID KbdBiosCleanup(VOID);
|
VOID KbdBiosCleanup(VOID);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
BOOLEAN VidBiosInitialize(VOID)
|
||||||
{
|
{
|
||||||
/* Some interrupts are in fact addresses to tables */
|
/* Some interrupts are in fact addresses to tables */
|
||||||
|
@ -1541,6 +1572,15 @@ BOOLEAN VidBiosInitialize(VOID)
|
||||||
((PULONG)BaseAddress)[0x43] = (ULONG)NULL;
|
((PULONG)BaseAddress)[0x43] = (ULONG)NULL;
|
||||||
((PULONG)BaseAddress)[0x44] = (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 */
|
/* Set the default video mode */
|
||||||
VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
|
VidBiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
|
||||||
|
|
||||||
|
|
|
@ -37,9 +37,12 @@ enum
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
VOID VidBiosSyncCursorPosition(VOID);
|
||||||
|
|
||||||
VOID WINAPI VidBiosVideoService(LPWORD Stack);
|
VOID WINAPI VidBiosVideoService(LPWORD Stack);
|
||||||
|
|
||||||
VOID VidBiosSyncCursorPosition(VOID);
|
VOID VidBiosDetachFromConsole(VOID);
|
||||||
|
VOID VidBiosAttachToConsole(VOID);
|
||||||
|
|
||||||
BOOLEAN VidBiosInitialize(VOID);
|
BOOLEAN VidBiosInitialize(VOID);
|
||||||
VOID VidBiosCleanup(VOID);
|
VOID VidBiosCleanup(VOID);
|
||||||
|
|
|
@ -44,6 +44,13 @@ do { \
|
||||||
#define CALL16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
|
#define CALL16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
|
||||||
#define INT16_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 */
|
/* 16-bit generic interrupt code for calling a 32-bit interrupt handler */
|
||||||
BYTE Int16To32[] =
|
BYTE Int16To32[] =
|
||||||
{
|
{
|
||||||
|
@ -52,12 +59,6 @@ BYTE Int16To32[] =
|
||||||
/* Push the value of the interrupt to be called */
|
/* Push the value of the interrupt to be called */
|
||||||
0x6A, 0xFF, // push i (patchable to 0x6A, 0xIntNum)
|
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 */
|
/* The BOP Sequence */
|
||||||
// BOP_SEQ:
|
// BOP_SEQ:
|
||||||
0xF8, // clc
|
0xF8, // clc
|
||||||
|
@ -74,7 +75,8 @@ BYTE Int16To32[] =
|
||||||
0xEB, 0xF5, // jmp BOP_SEQ (offset -11)
|
0xEB, 0xF5, // jmp BOP_SEQ (offset -11)
|
||||||
|
|
||||||
// EXIT:
|
// EXIT:
|
||||||
0x83, 0xC4, 0x08, // add sp, 8
|
// 0x44, 0x44, // inc sp, inc sp
|
||||||
|
0x83, 0xC4, 0x02, // add sp, 2
|
||||||
0xCF, // iret
|
0xCF, // iret
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "bop.h"
|
#include "bop.h"
|
||||||
|
|
||||||
#include "bios/bios.h"
|
#include "bios/bios.h"
|
||||||
#include "hardware/vga.h"
|
|
||||||
|
|
||||||
/* Extra PSDK/NDK Headers */
|
/* Extra PSDK/NDK Headers */
|
||||||
#include <ndk/obtypes.h>
|
#include <ndk/obtypes.h>
|
||||||
|
@ -138,8 +137,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
|
||||||
|
|
||||||
StartupInfo.cb = sizeof(StartupInfo);
|
StartupInfo.cb = sizeof(StartupInfo);
|
||||||
|
|
||||||
VgaRefreshDisplay();
|
VidBiosDetachFromConsole();
|
||||||
VgaDetachFromConsole(FALSE);
|
|
||||||
|
|
||||||
Result = CreateProcessA(NULL,
|
Result = CreateProcessA(NULL,
|
||||||
CommandLine,
|
CommandLine,
|
||||||
|
@ -171,9 +169,7 @@ static VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
|
||||||
dwExitCode = GetLastError();
|
dwExitCode = GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
VgaAttachToConsole();
|
VidBiosAttachToConsole();
|
||||||
VgaRefreshDisplay();
|
|
||||||
VidBiosSyncCursorPosition();
|
|
||||||
|
|
||||||
setAL((UCHAR)dwExitCode);
|
setAL((UCHAR)dwExitCode);
|
||||||
|
|
||||||
|
|
|
@ -24,65 +24,15 @@
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* 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 ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
CHAR DosReadCharacter(VOID)
|
CHAR DosReadCharacter(WORD FileHandle)
|
||||||
{
|
{
|
||||||
CHAR Character = '\0';
|
CHAR Character = '\0';
|
||||||
WORD BytesRead;
|
WORD BytesRead;
|
||||||
|
|
||||||
if (IsConsoleHandle(DosGetRealHandle(DOS_INPUT_HANDLE)))
|
/* Use the file reading function */
|
||||||
{
|
DosReadFile(FileHandle, &Character, 1, &BytesRead);
|
||||||
/* Call the BIOS */
|
|
||||||
Character = LOBYTE(BiosGetCharacter());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Use the file reading function */
|
|
||||||
DosReadFile(DOS_INPUT_HANDLE, &Character, sizeof(CHAR), &BytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Character;
|
return Character;
|
||||||
}
|
}
|
||||||
|
@ -117,12 +67,12 @@ BOOLEAN DosCheckInput(VOID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID DosPrintCharacter(CHAR Character)
|
VOID DosPrintCharacter(WORD FileHandle, CHAR Character)
|
||||||
{
|
{
|
||||||
WORD BytesWritten;
|
WORD BytesWritten;
|
||||||
|
|
||||||
/* Use the file writing function */
|
/* Use the file writing function */
|
||||||
DosWriteFile(DOS_OUTPUT_HANDLE, &Character, sizeof(CHAR), &BytesWritten);
|
DosWriteFile(FileHandle, &Character, 1, &BytesWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN DosBIOSInitialize(VOID)
|
BOOLEAN DosBIOSInitialize(VOID)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* COPYRIGHT: GPL - See COPYING in the top level directory
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS Virtual DOS Machine
|
* PROJECT: ReactOS Virtual DOS Machine
|
||||||
* FILE: dos.c
|
* FILE: dos/dos32krnl/dos.c
|
||||||
* PURPOSE: VDM DOS Kernel
|
* PURPOSE: VDM DOS Kernel
|
||||||
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
||||||
*/
|
*/
|
||||||
|
@ -29,8 +29,13 @@ static DWORD DiskTransferArea;
|
||||||
/*static*/ BYTE CurrentDrive;
|
/*static*/ BYTE CurrentDrive;
|
||||||
static CHAR LastDrive = 'E';
|
static CHAR LastDrive = 'E';
|
||||||
static CHAR CurrentDirectories[NUM_DRIVES][DOS_DIR_LENGTH];
|
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 BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
|
||||||
static BOOLEAN DosUmbLinked = FALSE;
|
static BOOLEAN DosUmbLinked = FALSE;
|
||||||
static WORD DosErrorLevel = 0x0000;
|
static WORD DosErrorLevel = 0x0000;
|
||||||
|
@ -431,6 +436,11 @@ static WORD DosCopyEnvironmentBlock(LPCVOID Environment, LPCSTR ProgramName)
|
||||||
return DestSegment;
|
return DestSegment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Taken from base/shell/cmd/console.c */
|
/* Taken from base/shell/cmd/console.c */
|
||||||
BOOL IsConsoleHandle(HANDLE hHandle)
|
BOOL IsConsoleHandle(HANDLE hHandle)
|
||||||
{
|
{
|
||||||
|
@ -455,7 +465,7 @@ BOOL IsConsoleHandle(HANDLE hHandle)
|
||||||
return GetConsoleMode(hHandle, &dwMode);
|
return GetConsoleMode(hHandle, &dwMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD DosOpenHandle(HANDLE Handle)
|
WORD DosOpenHandle(HANDLE Handle)
|
||||||
{
|
{
|
||||||
BYTE i;
|
BYTE i;
|
||||||
WORD DosHandle;
|
WORD DosHandle;
|
||||||
|
@ -482,10 +492,10 @@ static WORD DosOpenHandle(HANDLE Handle)
|
||||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||||
{
|
{
|
||||||
/* Check if this is the same handle */
|
/* Check if this is the same handle */
|
||||||
if (DosSystemFileTable[i] != Handle) continue;
|
if (DosSystemFileTable[i].Handle != Handle) continue;
|
||||||
|
|
||||||
/* Already in the table, reference it */
|
/* Already in the table, reference it */
|
||||||
DosSftRefCount[i]++;
|
DosSystemFileTable[i].RefCount++;
|
||||||
|
|
||||||
/* Set the JFT entry to that SFT index */
|
/* Set the JFT entry to that SFT index */
|
||||||
HandleTable[DosHandle] = i;
|
HandleTable[DosHandle] = i;
|
||||||
|
@ -498,11 +508,11 @@ static WORD DosOpenHandle(HANDLE Handle)
|
||||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||||
{
|
{
|
||||||
/* Make sure this is an empty table entry */
|
/* 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 */
|
/* Initialize the empty table entry */
|
||||||
DosSystemFileTable[i] = Handle;
|
DosSystemFileTable[i].Handle = Handle;
|
||||||
DosSftRefCount[i] = 1;
|
DosSystemFileTable[i].RefCount = 1;
|
||||||
|
|
||||||
/* Set the JFT entry to that SFT index */
|
/* Set the JFT entry to that SFT index */
|
||||||
HandleTable[DosHandle] = i;
|
HandleTable[DosHandle] = i;
|
||||||
|
@ -531,7 +541,7 @@ HANDLE DosGetRealHandle(WORD DosHandle)
|
||||||
if (HandleTable[DosHandle] == 0xFF) return INVALID_HANDLE_VALUE;
|
if (HandleTable[DosHandle] == 0xFF) return INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
/* Return the Win32 handle */
|
/* Return the Win32 handle */
|
||||||
return DosSystemFileTable[HandleTable[DosHandle]];
|
return DosSystemFileTable[HandleTable[DosHandle]].Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
||||||
|
@ -553,7 +563,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
||||||
DestinationTable[i] = (BYTE)i;
|
DestinationTable[i] = (BYTE)i;
|
||||||
|
|
||||||
/* Increase the reference count */
|
/* Increase the reference count */
|
||||||
DosSftRefCount[i]++;
|
DosSystemFileTable[i].RefCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
|
@ -570,7 +580,7 @@ static VOID DosCopyHandleTable(LPBYTE DestinationTable)
|
||||||
DestinationTable[i] = SourceTable[i];
|
DestinationTable[i] = SourceTable[i];
|
||||||
|
|
||||||
/* Increase the reference count */
|
/* 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 */
|
/* Decrement the reference count of the SFT entry */
|
||||||
SftIndex = HandleTable[DosHandle];
|
SftIndex = HandleTable[DosHandle];
|
||||||
DosSftRefCount[SftIndex]--;
|
DosSystemFileTable[SftIndex].RefCount--;
|
||||||
|
|
||||||
/* Check if the reference count fell to zero */
|
/* Check if the reference count fell to zero */
|
||||||
if (!DosSftRefCount[SftIndex])
|
if (!DosSystemFileTable[SftIndex].RefCount)
|
||||||
{
|
{
|
||||||
/* Close the file, it's no longer needed */
|
/* Close the file, it's no longer needed */
|
||||||
CloseHandle(DosSystemFileTable[SftIndex]);
|
CloseHandle(DosSystemFileTable[SftIndex].Handle);
|
||||||
|
|
||||||
/* Clear the handle */
|
/* Clear the handle */
|
||||||
DosSystemFileTable[SftIndex] = INVALID_HANDLE_VALUE;
|
DosSystemFileTable[SftIndex].Handle = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the entry in the JFT */
|
/* 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 */
|
/* Increment the reference count of the SFT entry */
|
||||||
SftIndex = HandleTable[OldHandle];
|
SftIndex = HandleTable[OldHandle];
|
||||||
DosSftRefCount[SftIndex]++;
|
DosSystemFileTable[SftIndex].RefCount++;
|
||||||
|
|
||||||
/* Make the new handle point to that SFT entry */
|
/* Make the new handle point to that SFT entry */
|
||||||
HandleTable[NewHandle] = SftIndex;
|
HandleTable[NewHandle] = SftIndex;
|
||||||
|
@ -650,260 +660,11 @@ static BOOLEAN DosDuplicateHandle(WORD OldHandle, WORD NewHandle)
|
||||||
return TRUE;
|
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)
|
static BOOLEAN DosChangeDrive(BYTE Drive)
|
||||||
{
|
{
|
||||||
|
@ -1279,6 +1040,36 @@ Cleanup:
|
||||||
return Result;
|
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,
|
WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
|
||||||
LPCSTR ProgramName,
|
LPCSTR ProgramName,
|
||||||
PDOS_EXEC_PARAM_BLOCK Parameters)
|
PDOS_EXEC_PARAM_BLOCK Parameters)
|
||||||
|
@ -1363,16 +1154,17 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
|
||||||
GetNextVDMCommand(&CommandInfo);
|
GetNextVDMCommand(&CommandInfo);
|
||||||
|
|
||||||
/* Load the executable */
|
/* Load the executable */
|
||||||
Result= DosLoadExecutable(LoadType,
|
Result = DosLoadExecutable(LoadType,
|
||||||
AppName,
|
AppName,
|
||||||
CmdLine,
|
CmdLine,
|
||||||
Env,
|
Env,
|
||||||
&Parameters->StackLocation,
|
&Parameters->StackLocation,
|
||||||
&Parameters->EntryPoint);
|
&Parameters->EntryPoint);
|
||||||
if (Result != ERROR_SUCCESS)
|
if (Result != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
DisplayMessage(L"Could not load '%S'. Error: %u", AppName, Result);
|
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;
|
break;
|
||||||
|
@ -1392,6 +1184,7 @@ WORD DosCreateProcess(DOS_EXEC_TYPE LoadType,
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
|
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
|
||||||
{
|
{
|
||||||
|
@ -1400,7 +1193,6 @@ VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
|
||||||
PDOS_MCB CurrentMcb;
|
PDOS_MCB CurrentMcb;
|
||||||
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
|
LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
|
||||||
PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
|
PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
|
||||||
VDM_COMMAND_INFO CommandInfo;
|
|
||||||
|
|
||||||
DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n",
|
DPRINT("DosTerminateProcess: Psp 0x%04X, ReturnCode 0x%02X\n",
|
||||||
Psp,
|
Psp,
|
||||||
|
@ -1451,10 +1243,13 @@ Done:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef STANDALONE
|
||||||
// FIXME: This is probably not the best way to do it
|
// FIXME: This is probably not the best way to do it
|
||||||
/* Check if this was a nested DOS task */
|
/* Check if this was a nested DOS task */
|
||||||
if (CurrentPsp != SYSTEM_PSP)
|
if (CurrentPsp != SYSTEM_PSP)
|
||||||
{
|
{
|
||||||
|
VDM_COMMAND_INFO CommandInfo;
|
||||||
|
|
||||||
/* Decrement the re-entry count */
|
/* Decrement the re-entry count */
|
||||||
CommandInfo.TaskId = SessionId;
|
CommandInfo.TaskId = SessionId;
|
||||||
CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
|
CommandInfo.VDMState = VDM_DEC_REENTER_COUNT;
|
||||||
|
@ -1468,6 +1263,7 @@ Done:
|
||||||
CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
|
CommandInfo.VDMState = VDM_FLAG_DONT_WAIT;
|
||||||
GetNextVDMCommand(&CommandInfo);
|
GetNextVDMCommand(&CommandInfo);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Save the return code - Normal termination */
|
/* Save the return code - Normal termination */
|
||||||
DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
|
DosErrorLevel = MAKEWORD(ReturnCode, 0x00);
|
||||||
|
@ -1500,12 +1296,12 @@ BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
|
||||||
* for a list of possible flags.
|
* for a list of possible flags.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (Handle == DosSystemFileTable[0])
|
if (Handle == DosSystemFileTable[DOS_INPUT_HANDLE].Handle)
|
||||||
{
|
{
|
||||||
/* Console input */
|
/* Console input */
|
||||||
InfoWord |= 1 << 0;
|
InfoWord |= 1 << 0;
|
||||||
}
|
}
|
||||||
else if (Handle == DosSystemFileTable[1])
|
else if (Handle == DosSystemFileTable[DOS_OUTPUT_HANDLE].Handle)
|
||||||
{
|
{
|
||||||
/* Console output */
|
/* Console output */
|
||||||
InfoWord |= 1 << 1;
|
InfoWord |= 1 << 1;
|
||||||
|
@ -1556,11 +1352,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
/* Read Character from STDIN with Echo */
|
/* Read Character from STDIN with Echo */
|
||||||
case 0x01:
|
case 0x01:
|
||||||
{
|
{
|
||||||
Character = DosReadCharacter();
|
// FIXME: Under DOS 2+, input / output handle may be redirected!!!!
|
||||||
DosPrintCharacter(Character);
|
Character = DosReadCharacter(DOS_INPUT_HANDLE);
|
||||||
|
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||||
|
|
||||||
/* Let the BOP repeat if needed */
|
// /* Let the BOP repeat if needed */
|
||||||
if (getCF()) break;
|
// if (getCF()) break;
|
||||||
|
|
||||||
setAL(Character);
|
setAL(Character);
|
||||||
break;
|
break;
|
||||||
|
@ -1569,8 +1366,9 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
/* Write Character to STDOUT */
|
/* Write Character to STDOUT */
|
||||||
case 0x02:
|
case 0x02:
|
||||||
{
|
{
|
||||||
|
// FIXME: Under DOS 2+, output handle may be redirected!!!!
|
||||||
Character = getDL();
|
Character = getDL();
|
||||||
DosPrintCharacter(Character);
|
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We return the output character (DOS 2.1+).
|
* We return the output character (DOS 2.1+).
|
||||||
|
@ -1588,7 +1386,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
{
|
{
|
||||||
// FIXME: Really read it from STDAUX!
|
// FIXME: Really read it from STDAUX!
|
||||||
DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
|
DPRINT1("INT 16h, 03h: Read character from STDAUX is HALFPLEMENTED\n");
|
||||||
setAL(DosReadCharacter());
|
// setAL(DosReadCharacter());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1597,7 +1395,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
{
|
{
|
||||||
// FIXME: Really write it to STDAUX!
|
// FIXME: Really write it to STDAUX!
|
||||||
DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
|
DPRINT1("INT 16h, 04h: Write character to STDAUX is HALFPLEMENTED\n");
|
||||||
DosPrintCharacter(getDL());
|
// DosPrintCharacter(getDL());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1616,10 +1414,12 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
{
|
{
|
||||||
Character = getDL();
|
Character = getDL();
|
||||||
|
|
||||||
|
// FIXME: Under DOS 2+, output handle may be redirected!!!!
|
||||||
|
|
||||||
if (Character != 0xFF)
|
if (Character != 0xFF)
|
||||||
{
|
{
|
||||||
/* Output */
|
/* Output */
|
||||||
DosPrintCharacter(Character);
|
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We return the output character (DOS 2.1+).
|
* We return the output character (DOS 2.1+).
|
||||||
|
@ -1634,7 +1434,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
if (DosCheckInput())
|
if (DosCheckInput())
|
||||||
{
|
{
|
||||||
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
|
Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
|
||||||
setAL(DosReadCharacter());
|
setAL(DosReadCharacter(DOS_INPUT_HANDLE));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1651,10 +1451,15 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
case 0x07:
|
case 0x07:
|
||||||
case 0x08:
|
case 0x08:
|
||||||
{
|
{
|
||||||
Character = DosReadCharacter();
|
// FIXME: Under DOS 2+, input handle may be redirected!!!!
|
||||||
|
Character = DosReadCharacter(DOS_INPUT_HANDLE);
|
||||||
|
|
||||||
/* Let the BOP repeat if needed */
|
// FIXME: For 0x07, do not check Ctrl-C/Break.
|
||||||
if (getCF()) 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);
|
setAL(Character);
|
||||||
break;
|
break;
|
||||||
|
@ -1667,7 +1472,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
|
|
||||||
while (*String != '$')
|
while (*String != '$')
|
||||||
{
|
{
|
||||||
DosPrintCharacter(*String);
|
DosPrintCharacter(DOS_OUTPUT_HANDLE, *String);
|
||||||
String++;
|
String++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1683,26 +1488,27 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
/* Read Buffered Input */
|
/* Read Buffered Input */
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
{
|
{
|
||||||
|
WORD Count = 0;
|
||||||
InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
|
InputBuffer = (PDOS_INPUT_BUFFER)SEG_OFF_TO_PTR(getDS(), getDX());
|
||||||
|
|
||||||
while (Stack[STACK_COUNTER] < InputBuffer->MaxLength)
|
DPRINT1("Read Buffered Input\n");
|
||||||
{
|
|
||||||
/* Try to read a character */
|
|
||||||
Character = DosReadCharacter();
|
|
||||||
|
|
||||||
/* If it's not ready yet, let the BOP repeat */
|
while (Count < InputBuffer->MaxLength)
|
||||||
if (getCF()) break;
|
{
|
||||||
|
/* Try to read a character (wait) */
|
||||||
|
Character = DosReadCharacter(DOS_INPUT_HANDLE);
|
||||||
|
|
||||||
/* Echo the character and append it to the buffer */
|
/* Echo the character and append it to the buffer */
|
||||||
DosPrintCharacter(Character);
|
DosPrintCharacter(DOS_OUTPUT_HANDLE, Character);
|
||||||
InputBuffer->Buffer[Stack[STACK_COUNTER]] = Character;
|
InputBuffer->Buffer[Count] = Character;
|
||||||
|
|
||||||
if (Character == '\r') break;
|
if (Character == '\r') break;
|
||||||
Stack[STACK_COUNTER]++;
|
Count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the length */
|
/* Update the length */
|
||||||
InputBuffer->Length = Stack[STACK_COUNTER];
|
InputBuffer->Length = Count;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1719,7 +1525,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
BYTE InputFunction = getAL();
|
BYTE InputFunction = getAL();
|
||||||
|
|
||||||
/* Flush STDIN buffer */
|
/* 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.
|
* 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 */
|
/* Read from File or Device */
|
||||||
case 0x3F:
|
case 0x3F:
|
||||||
{
|
{
|
||||||
WORD Handle = getBX();
|
|
||||||
LPBYTE Buffer = (LPBYTE)SEG_OFF_TO_PTR(getDS(), getDX());
|
|
||||||
WORD Count = getCX();
|
|
||||||
WORD BytesRead = 0;
|
WORD BytesRead = 0;
|
||||||
WORD ErrorCode = ERROR_SUCCESS;
|
WORD ErrorCode = DosReadFile(getBX(),
|
||||||
CHAR Character;
|
SEG_OFF_TO_PTR(getDS(), getDX()),
|
||||||
|
getCX(),
|
||||||
if (IsConsoleHandle(DosGetRealHandle(Handle)))
|
&BytesRead);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ErrorCode == ERROR_SUCCESS)
|
if (ErrorCode == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
@ -2215,6 +1985,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||||
setAX(ErrorCode);
|
setAX(ErrorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2358,7 +2129,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
WORD NewHandle;
|
WORD NewHandle;
|
||||||
HANDLE Handle = DosGetRealHandle(getBX());
|
HANDLE Handle = DosGetRealHandle(getBX());
|
||||||
|
|
||||||
if (Handle != INVALID_HANDLE_VALUE)
|
if (Handle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
/* The handle is invalid */
|
/* The handle is invalid */
|
||||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||||
|
@ -2491,6 +2262,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef STANDALONE
|
||||||
/* Execute */
|
/* Execute */
|
||||||
case 0x4B:
|
case 0x4B:
|
||||||
{
|
{
|
||||||
|
@ -2511,6 +2283,7 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Terminate With Return Code */
|
/* Terminate With Return Code */
|
||||||
case 0x4C:
|
case 0x4C:
|
||||||
|
@ -2540,8 +2313,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
getCX());
|
getCX());
|
||||||
|
|
||||||
setAX(Result);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2552,8 +2328,11 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea));
|
WORD Result = (WORD)demFileFindNext(FAR_POINTER(DiskTransferArea));
|
||||||
|
|
||||||
setAX(Result);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2581,6 +2360,23 @@ VOID WINAPI DosInt21h(LPWORD Stack)
|
||||||
break;
|
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 */
|
/* Get/Set Memory Management Options */
|
||||||
case 0x58:
|
case 0x58:
|
||||||
{
|
{
|
||||||
|
@ -2666,32 +2462,6 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
|
||||||
* for more information.
|
* 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 */
|
/* Save AX and BX */
|
||||||
USHORT AX = getAX();
|
USHORT AX = getAX();
|
||||||
USHORT BX = getBX();
|
USHORT BX = getBX();
|
||||||
|
@ -2707,12 +2477,11 @@ VOID WINAPI DosFastConOut(LPWORD Stack)
|
||||||
/* Restore AX and BX */
|
/* Restore AX and BX */
|
||||||
setBX(BX);
|
setBX(BX);
|
||||||
setAX(AX);
|
setAX(AX);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID WINAPI DosInt2Fh(LPWORD Stack)
|
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());
|
getAH(), getAL());
|
||||||
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
|
||||||
}
|
}
|
||||||
|
@ -2778,17 +2547,19 @@ BOOLEAN DosKRNLInitialize(VOID)
|
||||||
/* Initialize the SFT */
|
/* Initialize the SFT */
|
||||||
for (i = 0; i < DOS_SFT_SIZE; i++)
|
for (i = 0; i < DOS_SFT_SIZE; i++)
|
||||||
{
|
{
|
||||||
DosSystemFileTable[i] = INVALID_HANDLE_VALUE;
|
DosSystemFileTable[i].Handle = INVALID_HANDLE_VALUE;
|
||||||
DosSftRefCount[i] = 0;
|
DosSystemFileTable[i].RefCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get handles to standard I/O devices */
|
/* Get handles to standard I/O devices */
|
||||||
DosSystemFileTable[0] = GetStdHandle(STD_INPUT_HANDLE);
|
DosSystemFileTable[0].Handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
DosSystemFileTable[1] = GetStdHandle(STD_OUTPUT_HANDLE);
|
DosSystemFileTable[1].Handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
DosSystemFileTable[2] = GetStdHandle(STD_ERROR_HANDLE);
|
DosSystemFileTable[2].Handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
|
||||||
/* Initialize the reference counts */
|
/* Initialize the reference counts */
|
||||||
DosSftRefCount[0] = DosSftRefCount[1] = DosSftRefCount[2] = 1;
|
DosSystemFileTable[0].RefCount =
|
||||||
|
DosSystemFileTable[1].RefCount =
|
||||||
|
DosSystemFileTable[2].RefCount = 1;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,12 @@
|
||||||
#define USER_MEMORY_SIZE 0x8FFE
|
#define USER_MEMORY_SIZE 0x8FFE
|
||||||
#define SYSTEM_PSP 0x08
|
#define SYSTEM_PSP 0x08
|
||||||
#define SYSTEM_ENV_BLOCK 0x800
|
#define SYSTEM_ENV_BLOCK 0x800
|
||||||
#define INVALID_DOS_HANDLE 0xFFFF
|
|
||||||
#define DOS_INPUT_HANDLE 0
|
#define INVALID_DOS_HANDLE 0xFFFF
|
||||||
#define DOS_OUTPUT_HANDLE 1
|
#define DOS_INPUT_HANDLE 0
|
||||||
#define DOS_ERROR_HANDLE 2
|
#define DOS_OUTPUT_HANDLE 1
|
||||||
|
#define DOS_ERROR_HANDLE 2
|
||||||
|
|
||||||
#define DOS_SFT_SIZE 255
|
#define DOS_SFT_SIZE 255
|
||||||
#define SEGMENT_TO_MCB(seg) ((PDOS_MCB)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
|
#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 SEGMENT_TO_PSP(seg) ((PDOS_PSP)((ULONG_PTR)BaseAddress + TO_LINEAR((seg), 0)))
|
||||||
|
@ -172,9 +174,9 @@ do { \
|
||||||
* DOS BIOS Functions
|
* DOS BIOS Functions
|
||||||
* See bios.c
|
* See bios.c
|
||||||
*/
|
*/
|
||||||
CHAR DosReadCharacter(VOID);
|
CHAR DosReadCharacter(WORD FileHandle);
|
||||||
BOOLEAN DosCheckInput(VOID);
|
BOOLEAN DosCheckInput(VOID);
|
||||||
VOID DosPrintCharacter(CHAR Character);
|
VOID DosPrintCharacter(WORD FileHandle, CHAR Character);
|
||||||
|
|
||||||
BOOLEAN DosBIOSInitialize(VOID);
|
BOOLEAN DosBIOSInitialize(VOID);
|
||||||
|
|
||||||
|
@ -184,9 +186,15 @@ BOOLEAN DosBIOSInitialize(VOID);
|
||||||
* See dos.c
|
* See dos.c
|
||||||
*/
|
*/
|
||||||
BOOL IsConsoleHandle(HANDLE hHandle);
|
BOOL IsConsoleHandle(HANDLE hHandle);
|
||||||
|
WORD DosOpenHandle(HANDLE Handle);
|
||||||
HANDLE DosGetRealHandle(WORD DosHandle);
|
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 DosReadFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesRead);
|
||||||
WORD DosWriteFile(WORD FileHandle, LPVOID Buffer, WORD Count, LPWORD BytesWritten);
|
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);
|
VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment);
|
||||||
DWORD DosLoadExecutable(
|
DWORD DosLoadExecutable(
|
||||||
|
@ -202,6 +210,9 @@ WORD DosCreateProcess(
|
||||||
LPCSTR ProgramName,
|
LPCSTR ProgramName,
|
||||||
PDOS_EXEC_PARAM_BLOCK Parameters
|
PDOS_EXEC_PARAM_BLOCK Parameters
|
||||||
);
|
);
|
||||||
|
DWORD DosStartProcess(IN LPCSTR ExecutablePath,
|
||||||
|
IN LPCSTR CommandLine,
|
||||||
|
IN PVOID Environment);
|
||||||
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
|
VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode);
|
||||||
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);
|
BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle);
|
||||||
|
|
||||||
|
|
331
reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c
Normal file
331
reactos/subsystems/ntvdm/dos/dos32krnl/dosfiles.c
Normal 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);
|
||||||
|
}
|
|
@ -395,13 +395,22 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
|
||||||
/* Initialize the PS2 port */
|
/* Initialize the PS2 port */
|
||||||
PS2Initialize(ConsoleInput);
|
PS2Initialize(ConsoleInput);
|
||||||
|
|
||||||
|
/**************** ATTACH INPUT WITH CONSOLE *****************/
|
||||||
/* Start the input thread */
|
/* Start the input thread */
|
||||||
InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL);
|
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 */
|
/* Initialize the VGA */
|
||||||
// if (!VgaInitialize(ConsoleOutput)) return FALSE;
|
if (!VgaInitialize(ConsoleOutput))
|
||||||
VgaInitialize(ConsoleOutput);
|
{
|
||||||
|
DisplayMessage(L"Failed to initialize VGA support.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the software callback system and register the emulator BOPs */
|
/* Initialize the software callback system and register the emulator BOPs */
|
||||||
InitializeCallbacks();
|
InitializeCallbacks();
|
||||||
|
|
|
@ -34,13 +34,15 @@
|
||||||
#define EMULATOR_FLAG_VIP (1 << 20)
|
#define EMULATOR_FLAG_VIP (1 << 20)
|
||||||
#define EMULATOR_FLAG_ID (1 << 21)
|
#define EMULATOR_FLAG_ID (1 << 21)
|
||||||
|
|
||||||
#define STACK_VAR_B 0
|
//
|
||||||
#define STACK_VAR_A 1
|
// WARNING WARNING!!
|
||||||
#define STACK_COUNTER 2
|
// If you're changing the indices here, you then need to
|
||||||
#define STACK_INT_NUM 3
|
// also fix the BOP code in callback.c !!!!!!!!!!!!!!!!!
|
||||||
#define STACK_IP 4
|
//
|
||||||
#define STACK_CS 5
|
#define STACK_INT_NUM 0
|
||||||
#define STACK_FLAGS 6
|
#define STACK_IP 1
|
||||||
|
#define STACK_CS 2
|
||||||
|
#define STACK_FLAGS 3
|
||||||
|
|
||||||
|
|
||||||
/* Basic Memory Management */
|
/* Basic Memory Management */
|
||||||
|
|
|
@ -421,7 +421,7 @@ static VOID VgaUpdateCursorPosition(VOID)
|
||||||
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
|
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
|
||||||
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
|
VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
|
||||||
|
|
||||||
VidBiosSyncCursorPosition();
|
// VidBiosSyncCursorPosition();
|
||||||
VgaUpdateTextCursor();
|
VgaUpdateTextCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,61 +538,6 @@ static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
|
||||||
return TRUE;
|
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)
|
static BOOL IsConsoleHandle(HANDLE hHandle)
|
||||||
{
|
{
|
||||||
DWORD dwMode;
|
DWORD dwMode;
|
||||||
|
@ -1038,7 +983,10 @@ static BOOL VgaEnterTextMode(PCOORD Resolution)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else VgaUpdateCursorPosition();
|
else
|
||||||
|
{
|
||||||
|
VgaUpdateCursorPosition();
|
||||||
|
}
|
||||||
|
|
||||||
/* The active framebuffer is now the text framebuffer */
|
/* The active framebuffer is now the text framebuffer */
|
||||||
ConsoleFramebuffer = TextFramebuffer;
|
ConsoleFramebuffer = TextFramebuffer;
|
||||||
|
@ -1886,6 +1834,71 @@ VOID VgaResetPalette(VOID)
|
||||||
PaletteChanged = TRUE;
|
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)
|
BOOLEAN VgaInitialize(HANDLE TextHandle)
|
||||||
{
|
{
|
||||||
/* Save the default text-mode console output handle */
|
/* Save the default text-mode console output handle */
|
||||||
|
|
|
@ -58,6 +58,13 @@ VOID WINAPI ControlBop(LPWORD Stack)
|
||||||
|
|
||||||
VOID InitializeInt32(WORD BiosSegment)
|
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;
|
LPDWORD IntVecTable = (LPDWORD)BaseAddress;
|
||||||
LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0);
|
LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0);
|
||||||
USHORT i;
|
USHORT i;
|
||||||
|
@ -74,15 +81,6 @@ VOID InitializeInt32(WORD BiosSegment)
|
||||||
BiosCode[Offset++] = 0x6A; // push i
|
BiosCode[Offset++] = 0x6A; // push i
|
||||||
BiosCode[Offset++] = (UCHAR)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);
|
BopSeqOffset = COMMON_STUB_OFFSET - (Offset + 3);
|
||||||
|
|
||||||
BiosCode[Offset++] = 0xE9; // jmp near BOP_SEQ
|
BiosCode[Offset++] = 0xE9; // jmp near BOP_SEQ
|
||||||
|
@ -113,9 +111,11 @@ VOID InitializeInt32(WORD BiosSegment)
|
||||||
BiosCode[Offset++] = 0xF5;
|
BiosCode[Offset++] = 0xF5;
|
||||||
|
|
||||||
// EXIT:
|
// 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++] = 0xC4;
|
||||||
BiosCode[Offset++] = 0x08;
|
BiosCode[Offset++] = 0x02;
|
||||||
|
|
||||||
BiosCode[Offset++] = 0xCF; // iret
|
BiosCode[Offset++] = 0xCF; // iret
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
|
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Activate this line if you want to run NTVDM in standalone mode with:
|
|
||||||
* ntvdm.exe <program>
|
|
||||||
*/
|
|
||||||
// #define STANDALONE
|
|
||||||
|
|
||||||
/* VARIABLES ******************************************************************/
|
/* VARIABLES ******************************************************************/
|
||||||
|
|
||||||
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
|
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
|
||||||
|
@ -39,7 +33,10 @@ static HMENU hConsoleMenu = NULL;
|
||||||
static INT VdmMenuPos = -1;
|
static INT VdmMenuPos = -1;
|
||||||
static BOOLEAN ShowPointer = FALSE;
|
static BOOLEAN ShowPointer = FALSE;
|
||||||
|
|
||||||
|
#ifndef STANDALONE
|
||||||
ULONG SessionId = 0;
|
ULONG SessionId = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
HANDLE VdmTaskEvent = NULL;
|
HANDLE VdmTaskEvent = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -124,7 +121,7 @@ AppendMenuItems(HMENU hMenu,
|
||||||
static VOID
|
static VOID
|
||||||
CreateVdmMenu(HANDLE ConOutHandle)
|
CreateVdmMenu(HANDLE ConOutHandle)
|
||||||
{
|
{
|
||||||
hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
|
hConsoleMenu = ConsoleMenuControl(ConOutHandle,
|
||||||
ID_SHOWHIDE_MOUSE,
|
ID_SHOWHIDE_MOUSE,
|
||||||
ID_VDM_QUIT);
|
ID_VDM_QUIT);
|
||||||
if (hConsoleMenu == NULL) return;
|
if (hConsoleMenu == NULL) return;
|
||||||
|
@ -176,7 +173,8 @@ static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
VOID DisplayMessage(LPCWSTR Format, ...)
|
VOID
|
||||||
|
DisplayMessage(LPCWSTR Format, ...)
|
||||||
{
|
{
|
||||||
WCHAR Buffer[256];
|
WCHAR Buffer[256];
|
||||||
va_list Parameters;
|
va_list Parameters;
|
||||||
|
@ -188,7 +186,9 @@ VOID DisplayMessage(LPCWSTR Format, ...)
|
||||||
va_end(Parameters);
|
va_end(Parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
|
static BOOL
|
||||||
|
WINAPI
|
||||||
|
ConsoleCtrlHandler(DWORD ControlType)
|
||||||
{
|
{
|
||||||
switch (ControlType)
|
switch (ControlType)
|
||||||
{
|
{
|
||||||
|
@ -224,12 +224,14 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID ConsoleInitUI(VOID)
|
static VOID
|
||||||
|
ConsoleInitUI(VOID)
|
||||||
{
|
{
|
||||||
CreateVdmMenu(ConsoleOutput);
|
CreateVdmMenu(ConsoleOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID ConsoleCleanupUI(VOID)
|
static VOID
|
||||||
|
ConsoleCleanupUI(VOID)
|
||||||
{
|
{
|
||||||
/* Display again properly the mouse pointer */
|
/* Display again properly the mouse pointer */
|
||||||
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
||||||
|
@ -237,7 +239,97 @@ VOID ConsoleCleanupUI(VOID)
|
||||||
DestroyVdmMenu();
|
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;
|
HANDLE ConsoleInput = (HANDLE)Parameter;
|
||||||
INPUT_RECORD InputRecord;
|
INPUT_RECORD InputRecord;
|
||||||
|
@ -296,74 +388,10 @@ DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ConsoleInit(VOID)
|
#ifndef STANDALONE
|
||||||
{
|
static DWORD
|
||||||
/* Set the handler routine */
|
WINAPI
|
||||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
CommandThreadProc(LPVOID Parameter)
|
||||||
|
|
||||||
/* 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;
|
BOOLEAN First = TRUE;
|
||||||
DWORD Result;
|
DWORD Result;
|
||||||
|
@ -404,39 +432,25 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
|
||||||
if (!GetNextVDMCommand(&CommandInfo)) break;
|
if (!GetNextVDMCommand(&CommandInfo)) break;
|
||||||
|
|
||||||
/* Start the process from the command line */
|
/* Start the process from the command line */
|
||||||
DPRINT1("Starting '%s'...\n", AppName);
|
DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine);
|
||||||
|
Result = DosStartProcess(AppName, CmdLine, Env);
|
||||||
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, AppName, CmdLine, Env, NULL, NULL);
|
|
||||||
if (Result != ERROR_SUCCESS)
|
if (Result != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
|
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;
|
First = FALSE;
|
||||||
}
|
}
|
||||||
while (AcceptCommands);
|
while (AcceptCommands);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
INT wmain(INT argc, WCHAR *argv[])
|
INT
|
||||||
|
wmain(INT argc, WCHAR *argv[])
|
||||||
{
|
{
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
|
|
||||||
|
@ -459,6 +473,7 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
INT i;
|
INT i;
|
||||||
WCHAR *endptr;
|
WCHAR *endptr;
|
||||||
|
|
||||||
|
@ -530,27 +545,16 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Start the process from the command line */
|
/* Start the process from the command line */
|
||||||
DPRINT1("Starting '%s'...\n", ApplicationName);
|
DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine);
|
||||||
|
Result = DosStartProcess(ApplicationName,
|
||||||
Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
|
CommandLine,
|
||||||
ApplicationName,
|
GetEnvironmentStrings());
|
||||||
CommandLine,
|
|
||||||
GetEnvironmentStrings(),
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
if (Result != ERROR_SUCCESS)
|
if (Result != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
|
DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start simulation */
|
|
||||||
SetEvent(VdmTaskEvent);
|
|
||||||
EmulatorSimulate();
|
|
||||||
|
|
||||||
/* Perform another screen refresh */
|
|
||||||
VgaRefreshDisplay();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
|
|
|
@ -28,13 +28,22 @@
|
||||||
|
|
||||||
#include <vddsvc.h>
|
#include <vddsvc.h>
|
||||||
|
|
||||||
|
DWORD WINAPI SetLastConsoleEventActive(VOID);
|
||||||
|
|
||||||
#include <debug.h>
|
#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 ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
#ifndef STANDALONE
|
||||||
extern ULONG SessionId;
|
extern ULONG SessionId;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern HANDLE VdmTaskEvent;
|
extern HANDLE VdmTaskEvent;
|
||||||
|
|
||||||
VOID DisplayMessage(LPCWSTR Format, ...);
|
VOID DisplayMessage(LPCWSTR Format, ...);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue