[NTVDM]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 17 Jun 2013 00:00:36 +0000 (00:00 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 17 Jun 2013 00:00:36 +0000 (00:00 +0000)
Start of an implementation of a software DOS emulator.
Brought to you by Aleksandar Andrejevic. Good luck ;)

Remove the old language files. They will be recreated when the time comes.

svn path=/branches/ntvdm/; revision=59249

29 files changed:
subsystems/ntvdm/CMakeLists.txt
subsystems/ntvdm/bios.c [new file with mode: 0644]
subsystems/ntvdm/dos.c [new file with mode: 0644]
subsystems/ntvdm/emulator.c [new file with mode: 0644]
subsystems/ntvdm/lang/bg-BG.rc [deleted file]
subsystems/ntvdm/lang/cs-CZ.rc [deleted file]
subsystems/ntvdm/lang/de-DE.rc [deleted file]
subsystems/ntvdm/lang/en-US.rc [deleted file]
subsystems/ntvdm/lang/es-ES.rc [deleted file]
subsystems/ntvdm/lang/fr-FR.rc [deleted file]
subsystems/ntvdm/lang/hu-HU.rc [deleted file]
subsystems/ntvdm/lang/id-ID.rc [deleted file]
subsystems/ntvdm/lang/it-IT.rc [deleted file]
subsystems/ntvdm/lang/ja-JP.rc [deleted file]
subsystems/ntvdm/lang/no-NO.rc [deleted file]
subsystems/ntvdm/lang/pl-PL.rc [deleted file]
subsystems/ntvdm/lang/pt-BR.rc [deleted file]
subsystems/ntvdm/lang/ro-RO.rc [deleted file]
subsystems/ntvdm/lang/ru-RU.rc [deleted file]
subsystems/ntvdm/lang/sk-SK.rc [deleted file]
subsystems/ntvdm/lang/th-TH.rc [deleted file]
subsystems/ntvdm/lang/uk-UA.rc [deleted file]
subsystems/ntvdm/lang/zh-CN.rc [deleted file]
subsystems/ntvdm/lang/zh-TW.rc [deleted file]
subsystems/ntvdm/ntvdm.c
subsystems/ntvdm/ntvdm.h [new file with mode: 0644]
subsystems/ntvdm/ntvdm.rc
subsystems/ntvdm/resource.h
subsystems/ntvdm/rsrc.rc

index 7a1c6aa..af24b91 100644 (file)
@@ -1,11 +1,16 @@
 
-include_directories(.)
+include_directories(${REACTOS_SOURCE_DIR}/include/reactos/libs/softx86)
 
-add_executable(ntvdm
+list(APPEND SOURCE
+    bios.c
+    dos.c
+    emulator.c
     ntvdm.c
     ntvdm.rc)
 
-set_module_type(ntvdm win32cui)
-add_importlibs(ntvdm ntdll user32 gdi32 advapi32 msvcrt kernel32)
-add_dependencies(ntvdm ndk bugcodes)
+add_executable(ntvdm ${SOURCE})
+set_module_type(ntvdm win32cui UNICODE)
+target_link_libraries(ntvdm softx86 softx87)
+add_importlibs(ntvdm msvcrt user32 kernel32)
+add_dependencies(ntvdm softx86 softx87)
 add_cd_file(TARGET ntvdm DESTINATION reactos/system32 FOR all)
diff --git a/subsystems/ntvdm/bios.c b/subsystems/ntvdm/bios.c
new file mode 100644 (file)
index 0000000..1e9c5b4
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * COPYRIGHT:       GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Virtual DOS Machine
+ * FILE:            bios.c
+ * PURPOSE:         VDM BIOS
+ * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+#include "ntvdm.h"
+
+BYTE CursorRow, CursorCol;
+WORD ConsoleWidth, ConsoleHeight;
+
+BOOLEAN BiosInitialize()
+{
+    INT i;
+    WORD Offset = 0;
+    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+    CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
+    LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress);
+    LPBYTE BiosCode = (LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(BIOS_SEGMENT, 0));
+
+    /* Generate ISR stubs and fill the IVT */
+    for (i = 0; i < 256; i++)
+    {
+        IntVecTable[i * 2] = Offset;
+        IntVecTable[i * 2 + 1] = BIOS_SEGMENT;
+
+        if (i != SPECIAL_INT_NUM)
+        {
+            BiosCode[Offset++] = 0xFA; // cli
+
+            BiosCode[Offset++] = 0x6A; // push i
+            BiosCode[Offset++] = (BYTE)i;
+
+            BiosCode[Offset++] = 0xCD; // int SPECIAL_INT_NUM
+            BiosCode[Offset++] = SPECIAL_INT_NUM;
+
+            BiosCode[Offset++] = 0x83; // add sp, 2
+            BiosCode[Offset++] = 0xC4;
+            BiosCode[Offset++] = 0x02;
+        }
+
+        BiosCode[Offset++] = 0xCF; // iret
+    }
+
+    /* Get the console buffer info */
+    if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
+    {
+        return FALSE;
+    }
+
+    /* Set the initial cursor position and console size */
+    CursorCol = ConsoleInfo.dwCursorPosition.X;
+    CursorRow = ConsoleInfo.dwCursorPosition.Y;
+    ConsoleWidth = ConsoleInfo.dwSize.X;
+    ConsoleHeight = ConsoleInfo.dwSize.Y;
+
+    return TRUE;
+}
+
+static COORD BiosVideoAddressToCoord(ULONG Address)
+{
+    COORD Result = {0, 0};
+    CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
+    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+
+    if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
+    {
+        assert(0);
+        return Result;
+    }
+
+    Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % ConsoleInfo.dwSize.X;
+    Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / ConsoleInfo.dwSize.X;
+
+    return Result;
+}
+
+VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
+{
+    ULONG i;
+    COORD Coordinates;
+    DWORD CharsWritten;
+    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+
+    /* Loop through all the addresses */
+    for (i = StartAddress; i < EndAddress; i++)
+    {
+        /* Get the coordinates */
+        Coordinates = BiosVideoAddressToCoord(i);
+
+        /* Check if this is a character byte or an attribute byte */
+        if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
+        {
+            /* This is a regular character */
+            FillConsoleOutputCharacterA(ConsoleOutput,
+                                        *(PCHAR)((ULONG_PTR)BaseAddress + i),
+                                        sizeof(CHAR),
+                                        Coordinates,
+                                        &CharsWritten);
+        }
+        else
+        {
+            /*  This is an attribute */
+            FillConsoleOutputAttribute(ConsoleOutput,
+                                       *(PCHAR)((ULONG_PTR)BaseAddress + i),
+                                       sizeof(CHAR),
+                                       Coordinates,
+                                       &CharsWritten);
+        }
+    }
+}
+
+VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
+{
+    ULONG i;
+    COORD Coordinates;
+    WORD Attribute;
+    DWORD CharsWritten;
+    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+
+    /* Loop through all the addresses */
+    for (i = StartAddress; i < EndAddress; i++)
+    {
+        /* Get the coordinates */
+        Coordinates = BiosVideoAddressToCoord(i);
+
+        /* Check if this is a character byte or an attribute byte */
+        if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
+        {
+            /* This is a regular character */
+            ReadConsoleOutputCharacterA(ConsoleOutput,
+                                        (LPSTR)((ULONG_PTR)BaseAddress + i),
+                                        sizeof(CHAR),
+                                        Coordinates,
+                                        &CharsWritten);
+        }
+        else
+        {
+            /*  This is an attribute */
+            ReadConsoleOutputAttribute(ConsoleOutput,
+                                       &Attribute,
+                                       sizeof(CHAR),
+                                       Coordinates,
+                                       &CharsWritten);
+
+            *(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
+        }
+    }
+}
+
+VOID BiosVideoService()
+{
+    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+    INT CursorHeight;
+    BOOLEAN Invisible = FALSE;
+    COORD CursorPosition;
+    CONSOLE_CURSOR_INFO CursorInfo;
+    DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
+    DWORD Ecx = EmulatorGetRegister(EMULATOR_REG_CX);
+    DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
+
+    switch (LOBYTE(Eax))
+    {
+        /* Set Text-Mode Cursor Shape */
+        case 0x01:
+        {
+            /* Retrieve and validate the input */
+            Invisible = ((HIBYTE(Ecx) >> 5) & 0x03) ? TRUE : FALSE;
+            CursorHeight = (HIBYTE(Ecx) & 0x1F) - (LOBYTE(Ecx) & 0x1F);
+            if (CursorHeight < 1) CursorHeight = 1;
+            if (CursorHeight > 100) CursorHeight = 100;
+
+            /* Set the cursor */
+            CursorInfo.dwSize = (CursorHeight * 100) / CONSOLE_FONT_HEIGHT;
+            CursorInfo.bVisible = !Invisible;
+            SetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
+
+            break;
+        }
+
+        /* Set Cursor Position */
+        case 0x02:
+        {
+            CursorPosition.X = LOBYTE(Edx);
+            CursorPosition.Y = HIBYTE(Edx);
+
+            SetConsoleCursorPosition(ConsoleOutput, CursorPosition);
+            break;
+        }
+
+        /* Scroll Up Window */
+        case 0x06:
+        {
+            break;
+        }
+
+        /* Scroll Down Window */
+        case 0x07:
+        {
+            break;
+        }
+
+        /* Read Character And Attribute At Cursor Position */
+        case 0x08:
+        {
+            break;
+        }
+
+        /* Write Character And Attribute At Cursor Position */
+        case 0x09:
+        {
+            break;
+        }
+
+        /* Write Character Only At Cursor Position */
+        case 0x0A:
+        {
+            break;
+        }
+    }
+}
+
+/* EOF */
diff --git a/subsystems/ntvdm/dos.c b/subsystems/ntvdm/dos.c
new file mode 100644 (file)
index 0000000..e2402bb
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ * COPYRIGHT:       GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Virtual DOS Machine
+ * FILE:            dos.c
+ * PURPOSE:         VDM DOS Kernel
+ * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+#include "ntvdm.h"
+
+WORD CurrentPsp = SYSTEM_PSP, LastError = 0;
+
+static VOID DosCombineFreeBlocks()
+{
+    WORD Segment = FIRST_MCB_SEGMENT;
+    PDOS_MCB CurrentMcb, NextMcb;
+
+    /* Loop through all the blocks */
+    while (TRUE)
+    {
+        /* Get a pointer to the MCB */
+        CurrentMcb = SEGMENT_TO_MCB(Segment);
+
+        /* Ignore the last block */
+        if (CurrentMcb->BlockType == 'Z') break;
+
+        /* Get a pointer to the next MCB */
+        NextMcb = SEGMENT_TO_MCB(Segment + CurrentMcb->Size + 1);
+
+        /* If both this block and the next one are free, combine them */
+        if ((CurrentMcb->OwnerPsp == 0) && (NextMcb->OwnerPsp == 0))
+        {
+            CurrentMcb->Size += NextMcb->Size + 1;
+            CurrentMcb->BlockType = NextMcb->BlockType;
+
+            /* Invalidate the next MCB */
+            NextMcb->BlockType = 'I';
+
+            /* Try to combine the current block again with the next one */
+            continue;
+        }
+
+        /* Update the segment and continue */
+        Segment += CurrentMcb->Size + 1;
+    }
+}
+
+static WORD DosCopyEnvironmentBlock(WORD SourceSegment)
+{
+    PCHAR Ptr, SourceBuffer, DestBuffer = NULL;
+    ULONG TotalSize = 0;
+    WORD DestSegment;
+
+    Ptr = SourceBuffer = (PCHAR)((ULONG_PTR)BaseAddress + TO_LINEAR(SourceSegment, 0));
+
+    /* Calculate the size of the environment block */
+    while (*Ptr)
+    {
+        TotalSize += strlen(Ptr) + 1;
+        Ptr += strlen(Ptr) + 1;
+    }
+    TotalSize++;
+
+    /* Allocate the memory for the environment block */
+    DestSegment = DosAllocateMemory((TotalSize + 0x0F) >> 4);
+    if (!DestSegment) return 0;
+
+    Ptr = SourceBuffer;
+
+    DestBuffer = (PCHAR)((ULONG_PTR)BaseAddress + TO_LINEAR(DestSegment, 0));
+    while (*Ptr)
+    {
+        /* Copy the string */
+        strcpy(DestBuffer, Ptr);
+
+        /* Advance to the next string */
+        Ptr += strlen(Ptr) + 1;
+        DestBuffer += strlen(Ptr) + 1;
+    }
+
+    /* Set the final zero */
+    *DestBuffer = 0;
+
+    return DestSegment;
+}
+
+WORD DosAllocateMemory(WORD Size)
+{
+    WORD Result = 0, Segment = FIRST_MCB_SEGMENT;
+    PDOS_MCB CurrentMcb, NextMcb;
+
+    /* Find an unallocated block */
+    while (TRUE)
+    {
+        /* Get a pointer to the MCB */
+        CurrentMcb = SEGMENT_TO_MCB(Segment);
+
+        /* Make sure it's valid */
+        if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType != 'Z')
+        {
+            return 0;
+        }
+
+        /* Only check free blocks */
+        if (CurrentMcb->OwnerPsp != 0) goto Next;
+
+        /* Check if the block is big enough */
+        if (CurrentMcb->Size < Size) goto Next;
+
+        /* It is, update the smallest found so far */
+        if ((Result == 0) || (CurrentMcb->Size < SEGMENT_TO_MCB(Result)->Size))
+        {
+            Result = Segment;
+        }
+
+Next:
+        /* If this was the last MCB in the chain, quit. */
+        if (CurrentMcb->BlockType == 'Z') break;
+
+        /* Otherwise, update the segment and continue */
+        Segment += CurrentMcb->Size + 1;
+    }
+
+    /* If we didn't find a free block, return zero */
+    if (Result == 0) return 0;
+
+    /* Get a pointer to the MCB */
+    CurrentMcb = SEGMENT_TO_MCB(Result);
+
+    /* Check if the block is larger than requested */
+    if (CurrentMcb->Size > Size)
+    {
+        /* It is, split it into two blocks */
+        NextMcb = SEGMENT_TO_MCB(Result + Size + 1);
+
+        /* Initialize the new MCB structure */
+        NextMcb->BlockType = CurrentMcb->BlockType;
+        NextMcb->Size = Size - CurrentMcb->Size - 1;
+        NextMcb->OwnerPsp = 0;
+
+        /* Update the current block */
+        CurrentMcb->BlockType = 'M';
+        CurrentMcb->Size = Size;
+
+        /* Combine consecutive free blocks into larger blocks */
+        DosCombineFreeBlocks();
+    }
+
+    /* Take ownership of the block */
+    CurrentMcb->OwnerPsp = CurrentPsp;
+
+    return Result;
+}
+
+WORD DosResizeMemory(WORD Segment, WORD NewSize)
+{
+    WORD ReturnSize = 0, CurrentSeg;
+    PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment), CurrentMcb;
+    BOOLEAN FinalBlockUsed = FALSE;
+
+    /* We can't expand the last block */
+    if (Mcb->BlockType != 'M') return 0;
+
+    /* Check if need to expand or contract the block */
+    if (NewSize > Mcb->Size)
+    {
+        ReturnSize = Mcb->Size;
+
+        /* Get the segment of the next MCB */
+        CurrentSeg = Segment + Mcb->Size + 1;
+
+        /* Calculate the maximum amount of memory this block could expand to */
+        while (ReturnSize < NewSize)
+        {
+            /* Get the MCB */
+            CurrentMcb = SEGMENT_TO_MCB(CurrentSeg);
+
+            /* We can't expand the block over an allocated block */
+            if (CurrentMcb->OwnerPsp != 0) break;
+
+            ReturnSize += CurrentMcb->Size + 1;
+
+            /* Check if this is the last block */
+            if (CurrentMcb->BlockType == 'Z')
+            {
+                FinalBlockUsed = TRUE;
+                break;
+            }
+
+            /* Update the segment and continue */
+            CurrentSeg += CurrentMcb->Size + 1;
+        }
+
+        /* Check if we need to split the last block */
+        if (ReturnSize > NewSize)
+        {
+            /* Initialize the new MCB structure */
+            CurrentMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
+            CurrentMcb->BlockType = (FinalBlockUsed) ? 'Z' : 'M';
+            CurrentMcb->Size = ReturnSize - NewSize - 1;
+            CurrentMcb->OwnerPsp = 0;
+        }
+
+        /* Calculate the new size of the block */
+        ReturnSize = min(ReturnSize, NewSize);
+
+        /* Update the MCB */
+        if (FinalBlockUsed) Mcb->BlockType = 'Z';
+        Mcb->Size = ReturnSize;
+    }
+    else if (NewSize < Mcb->Size)
+    {
+        /* Just split the block */
+        CurrentMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
+        CurrentMcb->BlockType = Mcb->BlockType;
+        CurrentMcb->Size = Mcb->Size - NewSize - 1;
+        CurrentMcb->OwnerPsp = 0;
+
+        /* Update the MCB */
+        Mcb->BlockType = 'M';
+        Mcb->Size = NewSize;
+
+        ReturnSize = NewSize;
+    }
+
+    /* Combine consecutive free blocks into larger blocks */
+    DosCombineFreeBlocks();
+
+    return ReturnSize;
+}
+
+BOOLEAN DosFreeMemory(WORD Segment)
+{
+    PDOS_MCB Mcb = SEGMENT_TO_MCB(Segment);
+
+    /* Make sure the MCB is valid */
+    if (Mcb->BlockType != 'M' && Mcb->BlockType != 'Z') return FALSE;
+
+    /* Mark the block as free */
+    Mcb->OwnerPsp = 0;
+
+    /* Combine consecutive free blocks into larger blocks */
+    DosCombineFreeBlocks();
+
+    return TRUE;
+}
+
+WORD DosCreateFile(LPCSTR FilePath)
+{
+    // TODO: NOT IMPLEMENTED
+    return 0;
+}
+
+WORD DosOpenFile(LPCSTR FilePath)
+{
+    // TODO: NOT IMPLEMENTED
+    return 0;
+}
+
+VOID DosInitializePsp(WORD PspSegment, LPCSTR CommandLine, WORD ProgramSize, WORD Environment)
+{
+    INT i;
+    PDOS_PSP PspBlock = SEGMENT_TO_PSP(PspSegment);
+    LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
+
+    ZeroMemory(PspBlock, sizeof(DOS_PSP));
+
+    /* Set the exit interrupt */
+    PspBlock->Exit[0] = 0xCD; // int 0x20
+    PspBlock->Exit[1] = 0x20;
+
+    /* Set the program size */
+    PspBlock->MemSize = ProgramSize;
+
+    /* Save the interrupt vectors */
+    PspBlock->TerminateAddress = IntVecTable[0x22];
+    PspBlock->BreakAddress = IntVecTable[0x23];
+    PspBlock->CriticalAddress = IntVecTable[0x24];
+
+    /* Set the parent PSP */
+    PspBlock->ParentPsp = CurrentPsp;
+
+    /* Initialize the handle table */
+    for (i = 0; i < 20; i++) PspBlock->HandleTable[i] = 0xFF;
+
+    /* Did we get an environment segment? */
+    if (!Environment)
+    {
+        /* No, copy the one from the parent */
+        Environment = DosCopyEnvironmentBlock((CurrentPsp != SYSTEM_PSP)
+                                              ? SEGMENT_TO_PSP(CurrentPsp)->EnvBlock
+                                              : SYSTEM_ENV_BLOCK);
+    }
+
+    PspBlock->EnvBlock = Environment;
+
+    /* Set the handle table pointers to the internal handle table */
+    PspBlock->HandleTableSize = 20;
+    PspBlock->HandleTablePtr = MAKELONG(0x18, PspSegment);
+
+    /* Set the DOS version */
+    PspBlock->DosVersion = DOS_VERSION;
+
+    /* Set the far call opcodes */
+    PspBlock->FarCall[0] = 0xCD; // int 0x21
+    PspBlock->FarCall[1] = 0x21;
+    PspBlock->FarCall[2] = 0xCB; // retf
+
+    /* Set the command line */
+    PspBlock->CommandLineSize = strlen(CommandLine);
+    RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize);
+    PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r';
+}
+
+BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
+{
+    BOOLEAN Success = FALSE;
+    HANDLE FileHandle = INVALID_HANDLE_VALUE, FileMapping = NULL;
+    LPBYTE Address = NULL;
+    LPSTR ProgramFilePath, Parameters[128];
+    CHAR CommandLineCopy[128];
+    INT ParamCount = 0;
+    WORD Segment, FileSize;
+
+    /* Save a copy of the command line */
+    strcpy(CommandLineCopy, CommandLine);
+
+    /* Get the file name of the executable */
+    ProgramFilePath = strtok(CommandLineCopy, " \t");
+
+    /* Load the parameters in the local array */
+    while ((ParamCount < 256)
+           && ((Parameters[ParamCount] = strtok(NULL, " \t")) != NULL))
+    {
+        ParamCount++;
+    }
+
+    /* Open a handle to the executable */
+    FileHandle = CreateFileA(ProgramFilePath,
+                             GENERIC_READ,
+                             0,
+                             NULL,
+                             OPEN_EXISTING,
+                             FILE_ATTRIBUTE_NORMAL,
+                             NULL);
+    if (FileHandle == INVALID_HANDLE_VALUE) goto Cleanup;
+
+    /* Get the file size */
+    FileSize = GetFileSize(FileHandle, NULL);
+
+    /* Create a mapping object for the file */
+    FileMapping = CreateFileMapping(FileHandle,
+                                    NULL,
+                                    PAGE_READONLY,
+                                    0,
+                                    0,
+                                    NULL);
+    if (FileMapping == NULL) goto Cleanup;
+
+    /* Map the file into memory */
+    Address = (LPBYTE)MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0);
+    if (Address == NULL) goto Cleanup;
+
+    /* Check if this is an EXE file or a COM file */
+    if (Address[0] == 'M' && Address[1] == 'Z')
+    {
+        /* EXE file */
+
+        // TODO: NOT IMPLEMENTED
+        DisplayMessage(L"EXE files are not yet supported!");
+    }
+    else
+    {
+        /* COM file */
+
+        /* Allocate memory for the whole program and the PSP */
+        Segment = DosAllocateMemory((FileSize + sizeof(DOS_PSP)) >> 4);
+        if (Segment == 0) goto Cleanup;
+
+        /* Copy the program to Segment:0100 */
+        RtlCopyMemory((PVOID)((ULONG_PTR)BaseAddress
+                      + TO_LINEAR(Segment, 0x100)),
+                      Address,
+                      FileSize);
+
+        /* Initialize the PSP */
+        DosInitializePsp(Segment,
+                         CommandLine,
+                         (FileSize + sizeof(DOS_PSP)) >> 4,
+                         EnvBlock);
+
+        /* Set the initial segment registers */
+        EmulatorSetRegister(EMULATOR_REG_DS, Segment);
+        EmulatorSetRegister(EMULATOR_REG_ES, Segment);
+
+        /* Set the stack to the last word of the segment */
+        EmulatorSetStack(Segment, 0xFFFE);
+
+        /* Execute */
+        CurrentPsp = Segment;
+        EmulatorExecute(Segment, 0x100);
+
+        Success = TRUE;
+    }
+
+Cleanup:
+    /* Unmap the file*/
+    if (Address != NULL) UnmapViewOfFile(Address);
+
+    /* Close the file mapping object */
+    if (FileMapping != NULL) CloseHandle(FileMapping);
+
+    /* Close the file handle */
+    if (FileHandle != INVALID_HANDLE_VALUE) CloseHandle(FileHandle);
+
+    return Success;
+}
+
+VOID DosTerminateProcess(WORD Psp, BYTE ReturnCode)
+{
+    WORD McbSegment = FIRST_MCB_SEGMENT;
+    PDOS_MCB CurrentMcb;
+    LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
+    PDOS_PSP PspBlock = SEGMENT_TO_PSP(Psp);
+
+    /* Check if this PSP is it's own parent */
+    if (PspBlock->ParentPsp == Psp) goto Done;
+
+    // TODO: Close all handles opened by the process
+
+    /* Free the memory used by the process */
+    while (TRUE)
+    {
+        /* Get a pointer to the MCB */
+        CurrentMcb = SEGMENT_TO_MCB(McbSegment);
+
+        /* Make sure the MCB is valid */
+        if (CurrentMcb->BlockType != 'M' && CurrentMcb->BlockType !='Z') break;
+
+        /* If this block was allocated by the process, free it */
+        if (CurrentMcb->OwnerPsp == Psp) DosFreeMemory(McbSegment);
+
+        /* If this was the last block, quit */
+        if (CurrentMcb->BlockType == 'Z') break;
+
+        /* Update the segment and continue */
+        McbSegment += CurrentMcb->Size + 1;
+    }
+
+Done:
+    /* Restore the interrupt vectors */
+    IntVecTable[0x22] = PspBlock->TerminateAddress;
+    IntVecTable[0x23] = PspBlock->BreakAddress;
+    IntVecTable[0x24] = PspBlock->CriticalAddress;
+
+    /* Update the current PSP */
+    if (Psp == CurrentPsp)
+    {
+        CurrentPsp = PspBlock->ParentPsp;
+        if (CurrentPsp == SYSTEM_PSP) VdmRunning = FALSE;
+    }
+
+    /* Return control to the parent process */
+    EmulatorExecute(HIWORD(PspBlock->TerminateAddress),
+                    LOWORD(PspBlock->TerminateAddress));
+}
+
+CHAR DosReadCharacter()
+{
+    // TODO: STDIN can be redirected under DOS 2.0+
+    return _getch();
+}
+
+VOID DosPrintCharacter(CHAR Character)
+{
+    // TODO: STDOUT can be redirected under DOS 2.0+
+    if (Character == '\r') Character = '\n';
+    putchar(Character);
+}
+
+VOID DosInt20h(WORD CodeSegment)
+{
+    /* This is the exit interrupt */
+    DosTerminateProcess(CodeSegment, 0);
+}
+
+VOID DosInt21h(WORD CodeSegment)
+{
+    INT i;
+    CHAR Character;
+    PCHAR String;
+    PDOS_INPUT_BUFFER InputBuffer;
+    DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
+    DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
+    DWORD Ebx = EmulatorGetRegister(EMULATOR_REG_BX);
+    WORD DataSegment = EmulatorGetRegister(EMULATOR_REG_DS);
+    WORD ExtSegment = EmulatorGetRegister(EMULATOR_REG_ES);
+
+    /* Check the value in the AH register */
+    switch (HIBYTE(Eax))
+    {
+        /* Terminate Program */
+        case 0x00:
+        {
+            DosTerminateProcess(CodeSegment, 0);
+            break;
+        }
+
+        /* Read Character And Echo */
+        case 0x01:
+        {
+            Character = DosReadCharacter();
+            DosPrintCharacter(Character);
+            EmulatorSetRegister(EMULATOR_REG_AX, (Eax & 0xFFFFFF00) | Character);
+            break;
+        }
+
+        /* Print Character */
+        case 0x02:
+        {
+            DosPrintCharacter(LOBYTE(Edx));
+            break;
+        }
+
+        /* Read Character Without Echo */
+        case 0x08:
+        {
+            EmulatorSetRegister(EMULATOR_REG_AX,
+                               (Eax & 0xFFFFFF00) | DosReadCharacter());
+            break;
+        }
+
+        /* Print String */
+        case 0x09:
+        {
+            String = (PCHAR)((ULONG_PTR)BaseAddress
+                     + TO_LINEAR(DataSegment, LOWORD(Edx)));
+
+            while ((*String) != '$')
+            {
+                DosPrintCharacter(*String);
+                String++;
+            }
+
+            break;
+        }
+
+        /* Read Buffered Input */
+        case 0x0A:
+        {
+            InputBuffer = (PDOS_INPUT_BUFFER)((ULONG_PTR)BaseAddress
+                                              + TO_LINEAR(DataSegment,
+                                                          LOWORD(Edx)));
+
+            InputBuffer->Length = 0;
+            for (i = 0; i < InputBuffer->MaxLength; i ++)
+            {
+                Character = DosReadCharacter();
+                DosPrintCharacter(Character);
+                InputBuffer->Buffer[InputBuffer->Length] = Character;
+                if (Character == '\r') break;
+                InputBuffer->Length++;
+            }
+
+            break;
+        }
+
+        /* Allocate Memory */
+        case 0x48:
+        {
+            WORD Segment = DosAllocateMemory(LOWORD(Ebx));
+            if (Segment != 0)
+            {
+                EmulatorSetRegister(EMULATOR_REG_AX, Segment);
+                EmulatorClearFlag(EMULATOR_FLAG_CF);
+            }
+            else EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+            break;
+        }
+
+        /* Free Memory */
+        case 0x49:
+        {
+            if (DosFreeMemory(ExtSegment))
+            {
+                EmulatorClearFlag(EMULATOR_FLAG_CF);
+            }
+            else EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+            break;
+        }
+
+        /* Resize Memory Block */
+        case 0x4A:
+        {
+            WORD Size = DosResizeMemory(ExtSegment, LOWORD(Ebx));
+
+            if (Size != 0)
+            {
+                EmulatorSetRegister(EMULATOR_REG_BX, Size);
+                EmulatorClearFlag(EMULATOR_FLAG_CF);
+            }
+            else EmulatorSetFlag(EMULATOR_FLAG_CF);
+
+            break;
+        }
+
+        /* Terminate With Return Code */
+        case 0x4C:
+        {
+            DosTerminateProcess(CurrentPsp, LOBYTE(Eax));
+            break;
+        }
+
+        /* Unsupported */
+        default:
+        {
+            EmulatorSetFlag(EMULATOR_FLAG_CF);
+        }
+    }
+}
+
+VOID DosBreakInterrupt()
+{
+    VdmRunning = FALSE;
+}
+
+BOOLEAN DosInitialize()
+{
+    PDOS_MCB Mcb = SEGMENT_TO_MCB(FIRST_MCB_SEGMENT);
+    FILE *Stream;
+    WCHAR Buffer[256];
+    LPWSTR SourcePtr, Environment;
+    LPSTR AsciiString;
+    LPSTR DestPtr = (LPSTR)((ULONG_PTR)BaseAddress + TO_LINEAR(SYSTEM_ENV_BLOCK, 0));
+    DWORD AsciiSize;
+
+    /* Initialize the MCB */
+    Mcb->BlockType = 'Z';
+    Mcb->Size = (WORD)USER_MEMORY_SIZE;
+    Mcb->OwnerPsp = 0;
+
+    /* Get the environment strings */
+    SourcePtr = Environment = GetEnvironmentStringsW();
+    if (Environment == NULL) return FALSE;
+
+    /* Fill the DOS system environment block */
+    while (*SourcePtr)
+    {
+        /* Get the size of the ASCII string */
+        AsciiSize = WideCharToMultiByte(CP_ACP,
+                                        0,
+                                        SourcePtr,
+                                        -1,
+                                        NULL,
+                                        0,
+                                        NULL,
+                                        NULL);
+
+        /* Allocate memory for the ASCII string */
+        AsciiString = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AsciiSize);
+        if (AsciiString == NULL)
+        {
+            FreeEnvironmentStringsW(Environment);
+            return FALSE;
+        }
+
+        /* Convert to ASCII */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            SourcePtr,
+                            -1,
+                            AsciiString,
+                            AsciiSize,
+                            NULL,
+                            NULL);
+
+        /* Copy the string into DOS memory */
+        strcpy(DestPtr, AsciiString);
+
+        /* Free the memory */
+        HeapFree(GetProcessHeap(), 0, AsciiString);
+
+        /* Move to the next string */
+        SourcePtr += wcslen(SourcePtr) + 1;
+        DestPtr += strlen(AsciiString) + 1;
+    }
+
+    /* Free the memory allocated for environment strings */
+    FreeEnvironmentStringsW(Environment);
+
+    /* Read CONFIG.SYS */
+    Stream = _wfopen(DOS_CONFIG_PATH, L"r");
+    if (Stream != NULL)
+    {
+        while (fgetws(Buffer, 256, Stream))
+        {
+            // TODO: Parse the line
+        }
+        fclose(Stream);
+    }
+
+    return TRUE;
+}
+
+/* EOF */
diff --git a/subsystems/ntvdm/emulator.c b/subsystems/ntvdm/emulator.c
new file mode 100644 (file)
index 0000000..313067c
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * COPYRIGHT:       GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Virtual DOS Machine
+ * FILE:            emulator.c
+ * PURPOSE:         Minimal x86 machine emulator for the VDM
+ * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "ntvdm.h"
+#include <softx86/softx86.h>
+#include <softx86/softx87.h>
+
+softx86_ctx EmulatorContext;
+softx87_ctx FpuEmulatorContext;
+
+static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
+{
+    /* Make sure the requested address is valid */
+    if ((Address + Size) >= MAX_ADDRESS) return;
+
+    /* Are we reading some of the console video memory? */
+    if (((Address + Size) >= CONSOLE_VIDEO_MEM_START)
+        && (Address < CONSOLE_VIDEO_MEM_END))
+    {
+        /* Call the VDM BIOS to update the video memory */
+        BiosUpdateConsole(max(Address, CONSOLE_VIDEO_MEM_START),
+                          min(Address + Size, CONSOLE_VIDEO_MEM_END));
+    }
+
+    /* Read the data from the virtual address space and store it in the buffer */
+    RtlCopyMemory(Buffer, (LPVOID)((ULONG_PTR)BaseAddress + Address), Size);
+}
+
+static VOID EmulatorWriteMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
+{
+    /* Make sure the requested address is valid */
+    if ((Address + Size) >= MAX_ADDRESS) return;
+
+    /* Make sure we don't write to the ROM area */
+    if ((Address + Size) >= ROM_AREA_START && (Address < ROM_AREA_END)) return;
+
+    /* Read the data from the buffer and store it in the virtual address space */
+    RtlCopyMemory((LPVOID)((ULONG_PTR)BaseAddress + Address), Buffer, Size);
+
+    /* Check if we modified the console video memory */
+    if (((Address + Size) >= CONSOLE_VIDEO_MEM_START)
+        && (Address < CONSOLE_VIDEO_MEM_END))
+    {
+        /* Call the VDM BIOS to update the screen */
+        BiosUpdateConsole(max(Address, CONSOLE_VIDEO_MEM_START),
+                          min(Address + Size, CONSOLE_VIDEO_MEM_END));
+    }
+}
+
+static VOID EmulatorReadIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
+{
+    // TODO: NOT IMPLEMENTED!
+}
+
+static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
+{
+    // TODO: NOT IMPLEMENTED!
+}
+
+static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number)
+{
+    WORD StackSegment, StackPointer, CodeSegment, InstructionPointer;
+    BYTE IntNum;
+
+    /* Check if this is the special interrupt */
+    if (Number == SPECIAL_INT_NUM)
+    {
+        /* Get the SS:SP */
+        StackSegment = EmulatorContext.state->segment_reg[SX86_SREG_SS].val;
+        StackPointer = EmulatorContext.state->general_reg[SX86_REG_SP].val;
+
+        /* Get the interrupt number */
+        IntNum = *(LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(StackSegment, StackPointer));
+
+        /* Move the stack pointer forward one word to skip the interrupt number */
+        StackPointer += sizeof(WORD);
+
+        /* Get the CS:IP */
+        InstructionPointer = *(LPWORD)((ULONG_PTR)BaseAddress
+                             + TO_LINEAR(StackSegment, StackPointer));
+        CodeSegment = *(LPWORD)((ULONG_PTR)BaseAddress
+                      + TO_LINEAR(StackSegment, StackPointer + sizeof(WORD)));
+
+        /* Check if this was an exception */
+        if (IntNum < 8)
+        {
+            /* Display a message to the user */
+            DisplayMessage(L"Exception: %s occured at %04X:%04X",
+                           ExceptionName[IntNum],
+                           CodeSegment,
+                           InstructionPointer);
+
+            /* Stop the VDM */
+            VdmRunning = FALSE;
+            return;
+        }
+
+        switch (IntNum)
+        {
+            case VIDEO_BIOS_INTERRUPT:
+            {
+                /* This is the video BIOS interrupt, call the BIOS */
+                BiosVideoService();
+                break;
+            }
+            case 0x20:
+            {
+                DosInt20h(CodeSegment);
+                break;
+            }
+            case 0x21:
+            {
+                DosInt21h(CodeSegment);
+                break;
+            }
+            case 0x23:
+            {
+                DosBreakInterrupt();
+                break;
+            }
+        }
+    }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+BOOLEAN EmulatorInitialize()
+{
+    /* Allocate memory for the 16-bit address space */
+    BaseAddress = HeapAlloc(GetProcessHeap(), 0, MAX_ADDRESS);
+    if (BaseAddress == NULL) return FALSE;
+
+    /* Initialize the softx86 CPU emulator */
+    if (!softx86_init(&EmulatorContext, SX86_CPULEVEL_80186))
+    {
+        HeapFree(GetProcessHeap(), 0, BaseAddress);
+        return FALSE;
+    }
+
+    /* Initialize the softx87 FPU emulator*/
+    if(!softx87_init(&FpuEmulatorContext, SX87_FPULEVEL_8087))
+    {
+        softx86_free(&EmulatorContext);
+        HeapFree(GetProcessHeap(), 0, BaseAddress);
+        return FALSE;
+    }
+
+    /* Set memory read/write callbacks */
+    EmulatorContext.callbacks->on_read_memory = EmulatorReadMemory;
+    EmulatorContext.callbacks->on_write_memory = EmulatorWriteMemory;
+
+    /* Set MMIO read/write callbacks */
+    EmulatorContext.callbacks->on_read_io = EmulatorReadIo;
+    EmulatorContext.callbacks->on_write_io = EmulatorWriteIo;
+
+    /* Set interrupt callbacks */
+    EmulatorContext.callbacks->on_sw_int = EmulatorSoftwareInt;
+
+    /* Connect the emulated FPU to the emulated CPU */
+    softx87_connect_to_CPU(&EmulatorContext, &FpuEmulatorContext);
+
+    return TRUE;
+}
+
+VOID EmulatorSetStack(WORD Segment, WORD Offset)
+{
+    /* Call the softx86 API */
+    softx86_set_stack_ptr(&EmulatorContext, Segment, Offset);
+}
+
+VOID EmulatorExecute(WORD Segment, WORD Offset)
+{
+    /* Call the softx86 API */
+    softx86_set_instruction_ptr(&EmulatorContext, Segment, Offset);
+}
+
+VOID EmulatorInterrupt(BYTE Number)
+{
+    LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress);
+    UINT Segment, Offset;
+
+    /* Get the segment and offset */
+    Segment = HIWORD(IntVecTable[Number]);
+    Offset = LOWORD(IntVecTable[Number]);
+
+    /* Call the softx86 API */
+    softx86_make_simple_interrupt_call(&EmulatorContext, &Segment, &Offset);
+}
+
+ULONG EmulatorGetRegister(ULONG Register)
+{
+    if (Register < EMULATOR_REG_CS)
+    {
+        return EmulatorContext.state->general_reg[Register].val;
+    }
+    else
+    {
+        return EmulatorContext.state->segment_reg[(Register >> 3) - 1].val;
+    }
+}
+
+VOID EmulatorSetRegister(ULONG Register, ULONG Value)
+{
+    if (Register < EMULATOR_REG_CS)
+    {
+        EmulatorContext.state->general_reg[Register].val = Value;
+    }
+    else
+    {
+        EmulatorContext.state->segment_reg[(Register >> 3) - 1].val = Value;
+    }
+}
+
+BOOLEAN EmulatorGetFlag(ULONG Flag)
+{
+    return (EmulatorContext.state->reg_flags.val & Flag);
+}
+
+VOID EmulatorSetFlag(ULONG Flag)
+{
+    EmulatorContext.state->reg_flags.val |= Flag;
+}
+
+VOID EmulatorClearFlag(ULONG Flag)
+{
+    EmulatorContext.state->reg_flags.val &= ~Flag;
+}
+
+VOID EmulatorStep()
+{
+    /* Call the softx86 API */
+    softx86_step(&EmulatorContext);
+}
+
+VOID EmulatorCleanup()
+{
+    /* Free the memory allocated for the 16-bit address space */
+    if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
+
+    /* Free the softx86 CPU and FPU emulator */
+    softx86_free(&EmulatorContext);
+    softx87_free(&FpuEmulatorContext);
+}
+
+/* EOF */
diff --git a/subsystems/ntvdm/lang/bg-BG.rc b/subsystems/ntvdm/lang/bg-BG.rc
deleted file mode 100644 (file)
index 663207c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- */
-
-LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Ïîääðúæêà íà ÐåàêòÎÑ çà ïðèâèäíà ÄÎÑ ìàøèíà.\n"
-STRING_PromptMsg,       "Íàïèøåòå r<cr> çà ïóñêàíå, s<cr> çà ñïèðàíå èëè q<cr> çà èçõîä."
-END
diff --git a/subsystems/ntvdm/lang/cs-CZ.rc b/subsystems/ntvdm/lang/cs-CZ.rc
deleted file mode 100644 (file)
index 8db30d0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* FILE:        subsystems/ntvdm/lang/cs-CZ.rc
- * TRANSLATOR:  Radek Liska aka Black_Fox (radekliska at gmail dot com)
- * UPDATED:     2008-06-24
- */
-
-LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS podpora virtuálního DOS stroje.\n"
-STRING_PromptMsg,       "Napi\9ate r<cr> pro spu\9atìní, s<cr> pro vypnutí nebo q<cr> pro ukonèení."
-END
diff --git a/subsystems/ntvdm/lang/de-DE.rc b/subsystems/ntvdm/lang/de-DE.rc
deleted file mode 100644 (file)
index 423a74f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Translate into German.
- * By Rouven Wessling 2005 pentiumforever@gmail.com
- *                    2008 dark_shadow@gmx.at
- */
-
-LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS virtuelle DOS-Unterstützung.\n"
-STRING_PromptMsg,       "Drücken Sie r<cr> zum Starten, s<cr> zum Herunterfahren oder q<cr> zum Beenden."
-END
diff --git a/subsystems/ntvdm/lang/en-US.rc b/subsystems/ntvdm/lang/en-US.rc
deleted file mode 100644 (file)
index 9f86247..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- */
-
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS Virtual DOS Machine support.\n"
-STRING_PromptMsg,       "Type r<cr> to run, s<cr> to shutdown or q<cr> to quit now."
-END
diff --git a/subsystems/ntvdm/lang/es-ES.rc b/subsystems/ntvdm/lang/es-ES.rc
deleted file mode 100644 (file)
index 0741393..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Spanish Resource File
- * Reactos(c)2006 Samuel Serapion
- */
-
-LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Maquina virtual de DOS en ReactOS.\n"
-STRING_PromptMsg,       "Escriba r<cr> para correr, s<cr> para desactivar or q<cr> para salir ahora."
-END
diff --git a/subsystems/ntvdm/lang/fr-FR.rc b/subsystems/ntvdm/lang/fr-FR.rc
deleted file mode 100644 (file)
index 37b8693..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- */
-
-LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Aide de la Machine DOS Virtuel de ReactOS.\n"
-STRING_PromptMsg,       "Taper r<cr> pour démarrer, s<cr> pour éteindre ou q<cr> pour quitter maintenant."
-END
diff --git a/subsystems/ntvdm/lang/hu-HU.rc b/subsystems/ntvdm/lang/hu-HU.rc
deleted file mode 100644 (file)
index 8ca986f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Hungarian resource file for ntvdm
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- * Translation by Robert Horvath 2005 - talley at cubeclub.hu
- */
-
-LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS Virtuális DOS Gép támogatás.\n"
-STRING_PromptMsg,       "Futtatáshoz nyomd meg a r<cr>, leállításhoz a s<cr> vagy kilépéshez a q<cr> gombot."
-END
diff --git a/subsystems/ntvdm/lang/id-ID.rc b/subsystems/ntvdm/lang/id-ID.rc
deleted file mode 100644 (file)
index 6e6508c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-LANGUAGE LANG_INDONESIAN, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Dukungan ReactOS Virtual DOS Machine.\n"
-STRING_PromptMsg,       "Ketik r<cr> untuk menjalankan, s<cr> untuk mematikan atau q<cr> untuk keluar sekarang."
-END
diff --git a/subsystems/ntvdm/lang/it-IT.rc b/subsystems/ntvdm/lang/it-IT.rc
deleted file mode 100644 (file)
index 2748247..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
-* PROJECT:     ReactOS Virtual DOS Machine
-* LICENSE:     GPL - See COPYING in the top level directory
-* FILE:        subsystems/ntvdm/it-IT.rc
-* PURPOSE:     Italian Translation of subsystems/ntvdm/en-US.rc
-* PROGRAMMERS: Copyright (C) 2005 Magnus Olsen
-*              Copyright (C) 2007 Daniele Forsi (dforsi at gmail.com) Italian Translation
-*/
-
-LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Supporto di ReactOS per la macchina virtuale DOS.\n"
-STRING_PromptMsg,       "Digitare r<invio> per avviare, s<invio> per arrestare o q<invio> per abbandonare ora."
-END
diff --git a/subsystems/ntvdm/lang/ja-JP.rc b/subsystems/ntvdm/lang/ja-JP.rc
deleted file mode 100644 (file)
index aaacec4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- */
-
-LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS Virtual DOS Machine support.\n"
-STRING_PromptMsg,       "\8bN\93®\82·\82é\82É\82Í r<cr> \82ð\81A\83V\83\83\83b\83g\83_\83E\83\93\82·\82é\82É\82Í s<cr> \82ð\81A\8d¡\82·\82®\8fI\97¹\82³\82¹\82é\82É\82Í q<cr> \82ð\93ü\97Í\82µ\82Ä\82­\82¾\82³\82¢\81B"
-END
diff --git a/subsystems/ntvdm/lang/no-NO.rc b/subsystems/ntvdm/lang/no-NO.rc
deleted file mode 100644 (file)
index fded50c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- */
-
-LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS Vituell DOS Maskin støtte.\n"
-STRING_PromptMsg,       "Skriv r<cr> for å kjøre, s<cr> å avslutte eller q<cr> for å slutte nå."
-END
diff --git a/subsystems/ntvdm/lang/pl-PL.rc b/subsystems/ntvdm/lang/pl-PL.rc
deleted file mode 100644 (file)
index 30c3186..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *         translated by xrogers
- *         xxrogers@users.sourceforge.net
- *         https://sourceforge.net/projects/reactospl
- *         UTF-8 conversion by Caemyr (May, 2011) 
- */
-LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Wirtualna maszyna DOS dla ReactOS.\n"
-STRING_PromptMsg,       "Wciśnij r<cr> aby uruchomić, s<cr> aby wyłączyć lub q<cr>, aby zakończyć."
-END
diff --git a/subsystems/ntvdm/lang/pt-BR.rc b/subsystems/ntvdm/lang/pt-BR.rc
deleted file mode 100644 (file)
index 0c256c7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- */
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS subsistema para suporte DOS de 16 bits.\n"
-STRING_PromptMsg,       "Digite r<cr> para executar, s<cr> para desligar ou q<cr> para sair."
-END
diff --git a/subsystems/ntvdm/lang/ro-RO.rc b/subsystems/ntvdm/lang/ro-RO.rc
deleted file mode 100644 (file)
index 9ec32ba..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* 
- * FILE:             subsystems/ntvdm/lang/ro-RO.rc
- *                   ReactOS Project (http://www.reactos.org)
- * TRANSLATOR:       Fulea Ștefan (PM on ReactOS Forum at fulea.stefan)
- * CHANGE LOG:       2011-10-16  initial translation
- */
-
-LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Asistență pentru mașina virtuală DOS.\n"
-STRING_PromptMsg,       "Tastați r<cr> pentru a executa, s<cr> pentru a închide sau q<cr> pentru a ieși imediat."
-END
diff --git a/subsystems/ntvdm/lang/ru-RU.rc b/subsystems/ntvdm/lang/ru-RU.rc
deleted file mode 100644 (file)
index c446b86..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Moved all hardcoded strings to En.rc.
- * By Magnus Olsen  2005
- */
-
-LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Виртуальная машина поддержки DOS для ReactOS.\n"
-STRING_PromptMsg,       "Введите r<cr> для запуска, s<cr> для выключения или q<cr> выхода."
-END
diff --git a/subsystems/ntvdm/lang/sk-SK.rc b/subsystems/ntvdm/lang/sk-SK.rc
deleted file mode 100644 (file)
index f510a57..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/* TRANSLATOR:  Mário Kaèmár /Mario Kacmar/ aka Kario (kario@szm.sk)
- * DATE OF TR:  12-02-2008
- */
-
-LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Podpora virtuálneho DOSového stroja v systéme ReactOS.\n"
-STRING_PromptMsg,       "Napí\9ate r<cr> pre spustenie, s<cr> pre vypnutie alebo q<cr> pre okam\9eité skonèenie."
-END
diff --git a/subsystems/ntvdm/lang/th-TH.rc b/subsystems/ntvdm/lang/th-TH.rc
deleted file mode 100644 (file)
index 1eea0bc..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-LANGUAGE LANG_THAI, SUBLANG_DEFAULT
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ÃͧÃѺ¡Ò÷ӧҹÃкº´ÍÊàÊÁ×͹¢Í§ ReactOS\n"
-STRING_PromptMsg,       "Ẻ r<cr> à¾×èÍ·Ó§Ò¹, s<cr> à¾×èͻԴÃкºËÃ×Í q<cr> à¾×èÍÍÍ¡·Ñ¹·Õ"
-END
diff --git a/subsystems/ntvdm/lang/uk-UA.rc b/subsystems/ntvdm/lang/uk-UA.rc
deleted file mode 100644 (file)
index be23758..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * PROJECT:     Virtual DOS Machine
- * LICENSE:     GPL - See COPYING in the top level directory
- * FILE:        subsystems/ntvdm/Uk.rc
- * PURPOSE:     Ukraianian Language File for Virtual DOS Machine
- * TRANSLATOR:  Artem Reznikov
- */
-
-LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
-
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "Підтримка віртуальної машини DOS у ReactOS.\n"
-STRING_PromptMsg,       "Введіть r<cr> для запуску, s<cr> для закриття або q<cr>, щоб вийти зараз."
-END
diff --git a/subsystems/ntvdm/lang/zh-CN.rc b/subsystems/ntvdm/lang/zh-CN.rc
deleted file mode 100644 (file)
index 82b27de..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS ÐéÄâ DOS »úÖ§³Ö¡£\n"
-STRING_PromptMsg,       "ÊäÈë r<cr> ÒÔ±ãÔËÐУ¬s<cr> ÒÔ±ã¹Ø±Õ»òÕß q<cr> ÒÔ±ãÁ¢¼´Í˳ö¡£"
-END
diff --git a/subsystems/ntvdm/lang/zh-TW.rc b/subsystems/ntvdm/lang/zh-TW.rc
deleted file mode 100644 (file)
index fc1ad4b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL
-STRINGTABLE DISCARDABLE
-BEGIN
-
-STRING_WelcomeMsg,      "ReactOS µêÀÀ DOS ¾÷¤ä´©¡C\n"
-STRING_PromptMsg,       "Áä¤J r<cr> ¥H«K¹B¦æ¡A s<cr> ¥H«KÃö³¬©ÎªÌ q<cr> ¥H«K¥ß§Y°h¥X¡C"
-END
index 29cf573..40a5cdd 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
- * FILE:            subsys/ntvdm/ntvdm->c
+ * COPYRIGHT:       GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Virtual DOS Machine
+ * FILE:            ntvdm.c
  * PURPOSE:         Virtual DOS Machine
- * PROGRAMMER:      Robert Dickenson (robd@mok.lvcm.com)
- * UPDATE HISTORY:
- *                  Created 23/10/2002
+ * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  */
 
-/* INCLUDES *****************************************************************/
+#include "ntvdm.h"
 
-#include <stdarg.h>
-#define WIN32_NO_STATUS
-#include <windef.h>
-#include <winbase.h>
-#include <wincon.h>
-#include <winuser.h>
-#include <stdio.h>
-
-#include "resource.h"
-
-#define NDEBUG
-#include <debug.h>
-
-/* GLOBALS ******************************************************************/
-
-
-/* FUNCTIONS *****************************************************************/
-
-void PrintString(char* fmt,...)
-{
-   char buffer[512];
-   va_list ap;
-
-   va_start(ap, fmt);
-   vsprintf(buffer, fmt, ap);
-   va_end(ap);
-
-   OutputDebugStringA(buffer);
-}
-
-/*
-GetVersion
-GetVolumeInformationW
-GetWindowsDirectoryA
-GlobalMemoryStatus
-HeapAlloc
-HeapCreate
-HeapDestroy
-HeapFree
-HeapReAlloc
-
-GetNextVDMCommand
-ExitVDM
-RegisterConsoleVDM
-SetVDMCurrentDirectories
-VDMConsoleOperation
-WriteConsoleInputVDMW
-
-NtSetLdtEntries
-NtTerminateProcess
-
-NtMapViewOfSection
-NtUnmapViewOfSection
-
-NtVdmControl
- */
-typedef struct tag_VDM_CONFIG {
-    int dos_options;
-    int files;
-    int buffers;
-    WCHAR** device_list;
-//dos=high, umb
-//device=%SystemRoot%\system32\himem.sys
-//files=40
-} VDM_CONFIG, *PVDM_CONFIG;
-
-typedef struct tag_VDM_AUTOEXEC {
-    WCHAR** load_list;
-//lh %SystemRoot%\system32\mscdexnt.exe
-//lh %SystemRoot%\system32\redir
-//lh %SystemRoot%\system32\dosx
-} VDM_AUTOEXEC, *PVDM_AUTOEXEC;
-
-typedef struct tag_VDM_CONTROL_BLOCK {
-    HANDLE hHeap;
-    PVOID ImageMem;
-    VDM_CONFIG vdmConfig;
-    VDM_AUTOEXEC vdmAutoexec;
-    PROCESS_INFORMATION ProcessInformation;
-    CHAR CommandLine[MAX_PATH];
-    CHAR CurrentDirectory[MAX_PATH];
-
-} VDM_CONTROL_BLOCK, *PVDM_CONTROL_BLOCK;
-
-
-BOOL
-StartVDM(PVDM_CONTROL_BLOCK vdm)
+BOOLEAN VdmRunning = TRUE;
+LPVOID BaseAddress = NULL;
+LPCWSTR ExceptionName[] =
 {
-   BOOL Result;
-   STARTUPINFOA StartupInfo;
-
-   StartupInfo.cb = sizeof(StartupInfo);
-   StartupInfo.lpReserved = NULL;
-   StartupInfo.lpDesktop = NULL;
-   StartupInfo.lpTitle = NULL;
-   StartupInfo.dwFlags = 0;
-   StartupInfo.cbReserved2 = 0;
-   StartupInfo.lpReserved2 = 0;
-
-   Result = CreateProcessA(vdm->CommandLine,
-                          NULL,
-                          NULL,
-                          NULL,
-                          FALSE,
-                          DETACHED_PROCESS,
-                          NULL,
-                          NULL,
-                          &StartupInfo,
-                          &vdm->ProcessInformation);
-    if (!Result) {
-        PrintString("VDM: Failed to execute target process\n");
-        return FALSE;
-    }
-    WaitForSingleObject(vdm->ProcessInformation.hProcess, INFINITE);
-    CloseHandle(vdm->ProcessInformation.hProcess);
-    CloseHandle(vdm->ProcessInformation.hThread);
-    return TRUE;
-}
-
-BOOL
-ShutdownVDM(PVDM_CONTROL_BLOCK vdm)
+    L"Division By Zero",
+    L"Debug",
+    L"Unexpected Error",
+    L"Breakpoint",
+    L"Integer Overflow",
+    L"Bound Range Exceeded",
+    L"Invalid Opcode",
+    L"FPU Not Available"
+};
+
+VOID DisplayMessage(LPCWSTR Format, ...)
 {
-    BOOL result = TRUE;
+    WCHAR Buffer[256];
+    va_list Parameters;
 
-    return result;
+    va_start(Parameters, Format);
+    _vsnwprintf(Buffer, 256, Format, Parameters);
+    MessageBox(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
+    va_end(Parameters);
 }
 
-BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm)
+BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
 {
-    BOOL result = TRUE;
-    DWORD dwError;
-    HANDLE hFile;
-
-    hFile = CreateFileW(L"\\system32\\config.nt",
-                        GENERIC_READ,
-                        FILE_SHARE_READ,
-                        NULL,
-                        OPEN_ALWAYS /*OPEN_EXISTING*/,
-                        FILE_ATTRIBUTE_NORMAL,
-                        0);
-    dwError = GetLastError();
-    if (hFile == INVALID_HANDLE_VALUE) {
-        // error with file path or system problem?
-    } else {
-        if (dwError == 0L) {
-            // we just created a new file, perhaps we should set/write some defaults?
-        }
-        if (dwError == ERROR_ALREADY_EXISTS) {
-            // read the line entries and cache in some struct...
+    switch (ControlType)
+    {
+        case CTRL_C_EVENT:
+        case CTRL_BREAK_EVENT:
+        {
+            /* Perform interrupt 0x23 */
+            EmulatorInterrupt(0x23);
         }
-        CloseHandle(hFile);
-    }
-
-    hFile = CreateFileW(L"\\system32\\autoexec.nt",
-                        GENERIC_READ,
-                        FILE_SHARE_READ,
-                        NULL,
-                        OPEN_ALWAYS,
-                        FILE_ATTRIBUTE_NORMAL,
-                        0);
-    dwError = GetLastError();
-    if (hFile == INVALID_HANDLE_VALUE) {
-        // error with file path or system problem?
-    } else {
-        if (dwError == 0L) {
-            // we just created a new file, perhaps we should set/write some defaults?
-        }
-        if (dwError == ERROR_ALREADY_EXISTS) {
-            // read the line entries and cache in some struct...
-        }
-        CloseHandle(hFile);
-    }
-
-       return result;
-}
-
-BOOL
-LoadConfigDriversForVDM(PVDM_CONFIG vdmConfig)
-{
-    BOOL result = TRUE;
-
-       return result;
-}
-
-BOOL
-SetConfigOptionsForVDM(PVDM_AUTOEXEC vdmAutoexec)
-{
-    BOOL result = TRUE;
-
-       return result;
-}
-
-BOOL
-CreateVDM(PVDM_CONTROL_BLOCK vdm)
-{
-//    BOOL result = TRUE;
-    SYSTEM_INFO inf;
-    MEMORYSTATUS stat;
-
-
-    GlobalMemoryStatus(&stat);
-    if (stat.dwLength != sizeof(MEMORYSTATUS)) {
-        printf("WARNING: GlobalMemoryStatus() returned unknown structure version, size %ld, expected %d.\n", stat.dwLength, sizeof(stat));
-    } else {
-        printf("Memory Load: %ld percent in use.\n", stat.dwMemoryLoad);
-        printf("\t%ld total bytes physical memory.\n", stat.dwTotalPhys);
-        printf("\t%ld available physical memory.\n", stat.dwAvailPhys);
-        printf("\t%ld total bytes paging file.\n", stat.dwTotalPageFile);
-        printf("\t%ld available paging file.\n", stat.dwAvailPageFile);
-        printf("\t%lx total bytes virtual memory.\n", stat.dwTotalVirtual);
-        printf("\t%lx available bytes virtual memory.\n", stat.dwAvailVirtual);
-
-#define OUT_OF_HEADROOM 90
-        if (stat.dwMemoryLoad > OUT_OF_HEADROOM) {
-            DPRINT("VDM: system resources deemed to low to start VDM.\n");
-            //SetLastError();
-            return FALSE;
+        default:
+        {
+            /* Stop the VDM if the user logs out or closes the console */
+            VdmRunning = FALSE;
         }
-
-    }
-
-    GetSystemInfo(&inf);
-    vdm->hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
-    if (vdm->hHeap == NULL) {
-        DPRINT("VDM: failed to create heap.\n");
-        return FALSE;
-    }
-
-#define DEFAULT_VDM_IMAGE_SIZE 2000000
-    vdm->ImageMem = HeapAlloc(vdm->hHeap, 0, DEFAULT_VDM_IMAGE_SIZE);
-    if (vdm->ImageMem == NULL) {
-        DPRINT("VDM: failed to allocate image memory from heap %x.\n", vdm->hHeap);
-        HeapDestroy(vdm->hHeap);
-        vdm->hHeap = NULL;
-        return FALSE;
     }
     return TRUE;
 }
 
-BOOL
-DestroyVDM(PVDM_CONTROL_BLOCK vdm)
+INT wmain(INT argc, WCHAR *argv[])
 {
-    BOOL result = TRUE;
-
-    if (vdm->ImageMem != NULL) {
-        if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) {
-            DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap);
-            result = FALSE;
-        }
-        vdm->ImageMem = NULL;
-    }
-    if (vdm->hHeap != NULL) {
-        if (!HeapDestroy(vdm->hHeap)) {
-            DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap);
-            result = FALSE;
+    INT i;
+    BOOLEAN PrintUsage = TRUE;
+    CHAR CommandLine[128];
+
+    /* Set the handler routine */
+    SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
+
+    /* Parse the command line arguments */
+    for (i = 1; i < argc; i++)
+    {
+        if (argv[i][0] != L'-' && argv[i][0] != L'/') continue;
+
+        switch (argv[i][1])
+        {
+            case L'f':
+            case L'F':
+            {
+                if (argv[i+1] != NULL)
+                {
+                    /* The DOS command line must be ASCII */
+                    WideCharToMultiByte(CP_ACP, 0, argv[i+1], -1, CommandLine, 128, NULL, NULL);
+
+                    /* This is the only mandatory parameter */
+                    PrintUsage = FALSE;
+                }
+                break;
+            }
+            default:
+            {
+                wprintf(L"Unknown option: %s", argv[i]);
+            }
         }
-        vdm->hHeap = NULL;
     }
-    return result;
-}
 
-int WINAPI
-WinMain(HINSTANCE hInstance,  HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
-{
-    VDM_CONTROL_BLOCK VdmCB;
-    DWORD Result;
-    ULONG i;
-    BOOL vdmStarted = FALSE;
-
-    WCHAR WelcomeMsg[RC_STRING_MAX_SIZE];
-    WCHAR PromptMsg[RC_STRING_MAX_SIZE];
-    CHAR InputBuffer[255];
-
-    LoadStringW( GetModuleHandle(NULL), STRING_WelcomeMsg, WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0]));
-    LoadStringW( GetModuleHandle(NULL), STRING_PromptMsg, PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0]));
-
-    AllocConsole();
-    SetConsoleTitleW(L"ntvdm");
-
-    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
-                 WelcomeMsg, lstrlenW(WelcomeMsg),  // wcslen(WelcomeMsg),
-                 &Result, NULL);
-
-    if (!CreateVDM(&VdmCB)) {
-        DPRINT("VDM: failed to create VDM.\n");
-        //SetLastError();
-        return 2;
+    if (PrintUsage)
+    {
+        wprintf(L"ReactOS Virtual DOS Machine\n\n");
+        wprintf(L"Usage: NTVDM /F <PROGRAM>\n");
+        return 0;
     }
 
-       ReadConfigForVDM(&VdmCB);
+    if (!EmulatorInitialize()) return 1;
 
-    if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) {
-        DPRINT("VDM: failed to load configuration drivers.\n");
-        //SetLastError();
-        return 2;
+    /* Initialize the system BIOS */
+    if (!BiosInitialize())
+    {
+        wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
+        goto Cleanup;
     }
-    if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) {
-        DPRINT("VDM: failed to set configuration options.\n");
-        //SetLastError();
-        return 3;
-    }
-
-    GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH);
-    strcat(VdmCB.CommandLine, "\\hello.exe");
-    GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH);
-
-    for (;;) {
-        WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
-                     PromptMsg, lstrlenW(PromptMsg),  // wcslen(PromptMsg),
-                     &Result, NULL);
-        i = 0;
-        do {
-            ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
-                        &InputBuffer[i], 1,
-                        &Result, NULL);
-            if (++i >= (sizeof(InputBuffer) - 1)) {
-                break;
-            }
-        } while (InputBuffer[i - 1] != '\n');
-        InputBuffer[i - 1] = '\0';
 
-        if (InputBuffer[0] == 'r' || InputBuffer[0] == 'R') {
-            if (!vdmStarted) {
-                if (StartVDM(&VdmCB)) {
-                    vdmStarted = TRUE;
-                } else {
-                    DPRINT("VDM: failed to start.\n");
-                }
-            } else {
-                DPRINT("VDM: already started.\n");
-            }
-        }
-        if (InputBuffer[0] == 's' || InputBuffer[0] == 'S') {
-            if (vdmStarted) {
-                if (ShutdownVDM(&VdmCB)) {
-                    vdmStarted = FALSE;
-                } else {
-                    DPRINT("VDM: failed to shutdown.\n");
-                }
-            } else {
-                DPRINT("VDM: not started.\n");
-            }
-        }
-        if (InputBuffer[0] == 'q' || InputBuffer[0] == 'Q') {
-            break;
-        }
+    /* Initialize the VDM DOS kernel */
+    if (!DosInitialize())
+    {
+        wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n");
+        goto Cleanup;
     }
 
-    if (!ShutdownVDM(&VdmCB)) {
-        DPRINT("VDM: failed to cleanly shutdown VDM.\n");
-        //SetLastError();
-        return 5;
+    /* Start the process from the command line */
+    if (!DosCreateProcess(CommandLine, 0))
+    {
+        DisplayMessage(L"Could not start program: %S", CommandLine);
+        return -1;
     }
 
-    if (!DestroyVDM(&VdmCB)) {
-        DPRINT("VDM: failed to cleanly destroy VDM.\n");
-        //SetLastError();
-        return 6;
-    }
+    /* Main loop */
+    while (VdmRunning) EmulatorStep();
+
+Cleanup:
+    EmulatorCleanup();
 
-    ExitProcess(0);
     return 0;
 }
+
+/* EOF */
diff --git a/subsystems/ntvdm/ntvdm.h b/subsystems/ntvdm/ntvdm.h
new file mode 100644 (file)
index 0000000..b3bfe50
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * COPYRIGHT:       GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Virtual DOS Machine
+ * FILE:            ntvdm.h
+ * PURPOSE:         Header file to define commonly used stuff
+ * PROGRAMMERS:     Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <windows.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+#include <assert.h>
+#include <stdarg.h>
+
+/* DEFINES ********************************************************************/
+
+#define TO_LINEAR(seg, off) (((seg) << 4) + (off))
+#define MAX_SEGMENT 0xFFFF
+#define MAX_OFFSET 0xFFFF
+#define MAX_ADDRESS TO_LINEAR(MAX_SEGMENT, MAX_OFFSET)
+#define ROM_AREA_START 0xC0000
+#define ROM_AREA_END 0xFFFFF
+#define BIOS_SEGMENT 0xF000
+#define VIDEO_BIOS_INTERRUPT 0x10
+#define SPECIAL_INT_NUM 0xFF
+#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)))
+
+/* DOS constants */
+#define DOS_VERSION 0x0600
+#define DOS_CONFIG_PATH L"%SystemRoot%\\system32\\CONFIG.NT"
+#define DOS_COMMAND_INTERPRETER L"%SystemRoot%\\system32\\COMMAND.COM /k %SystemRoot%\\system32\\AUTOEXEC.NT"
+#define FIRST_MCB_SEGMENT 0x1000
+#define USER_MEMORY_SIZE 0x8FFFF
+#define SYSTEM_PSP 0x08
+#define SYSTEM_ENV_BLOCK 0x800
+
+/* System console constants */
+#define CONSOLE_FONT_HEIGHT 8
+#define CONSOLE_VIDEO_MEM_START 0xB8000
+#define CONSOLE_VIDEO_MEM_END 0xBFFFF
+
+#define EMULATOR_FLAG_CF (1 << 0)
+#define EMULATOR_FLAG_PF (1 << 2)
+#define EMULATOR_FLAG_AF (1 << 4)
+#define EMULATOR_FLAG_ZF (1 << 6)
+#define EMULATOR_FLAG_SF (1 << 7)
+#define EMULATOR_FLAG_TF (1 << 8)
+#define EMULATOR_FLAG_IF (1 << 9)
+#define EMULATOR_FLAG_DF (1 << 10)
+#define EMULATOR_FLAG_OF (1 << 11)
+#define EMULATOR_FLAG_NT (1 << 14)
+#define EMULATOR_FLAG_RF (1 << 16)
+#define EMULATOR_FLAG_VM (1 << 17)
+#define EMULATOR_FLAG_AC (1 << 18)
+#define EMULATOR_FLAG_VIF (1 << 19)
+#define EMULATOR_FLAG_VIP (1 << 20)
+#define EMULATOR_FLAG_ID (1 << 21)
+
+typedef enum
+{
+    EMULATOR_REG_AX,
+    EMULATOR_REG_CX,
+    EMULATOR_REG_DX,
+    EMULATOR_REG_BX,
+    EMULATOR_REG_SI,
+    EMULATOR_REG_DI,
+    EMULATOR_REG_SP,
+    EMULATOR_REG_BP,
+    EMULATOR_REG_CS,
+    EMULATOR_REG_SS,
+    EMULATOR_REG_DS,
+    EMULATOR_REG_ES,
+    EMULATOR_REG_FS,
+    EMULATOR_REG_GS
+} EMULATOR_REGISTER;
+
+#pragma pack(push, 1)
+
+typedef struct _DOS_MCB
+{
+    CHAR BlockType;
+    WORD OwnerPsp;
+    WORD Size;
+    BYTE Unused[3];
+    CHAR Name[8];
+} DOS_MCB, *PDOS_MCB;
+
+typedef struct _DOS_FCB
+{
+    BYTE DriveNumber;
+    CHAR FileName[8];
+    CHAR FileExt[3];
+    WORD BlockNumber;
+    WORD RecordSize;
+    DWORD FileSize;
+    WORD LastWriteDate;
+    WORD LastWriteTime;
+    BYTE Reserved[8];
+    BYTE BlockRecord;
+    BYTE RecordNumber[3];
+} DOS_FCB, *PDOS_FCB;
+
+typedef struct _DOS_PSP
+{
+    BYTE Exit[2];
+    WORD MemSize;
+    BYTE Reserved0[6];
+    DWORD TerminateAddress;
+    DWORD BreakAddress;
+    DWORD CriticalAddress;
+    WORD ParentPsp;
+    BYTE HandleTable[20];
+    WORD EnvBlock;
+    DWORD LastStack;
+    WORD HandleTableSize;
+    DWORD HandleTablePtr;
+    DWORD PreviousPsp;
+    DWORD Reserved1;
+    WORD DosVersion;
+    BYTE Reserved2[14];
+    BYTE FarCall[3];
+    BYTE Reserved3[9];
+    DOS_FCB Fcb;
+    BYTE CommandLineSize;
+    CHAR CommandLine[127];
+} DOS_PSP, *PDOS_PSP;
+
+typedef struct _DOS_SFT_ENTRY
+{
+    WORD ReferenceCount;
+    WORD Mode;
+    BYTE Attribute;
+    WORD DeviceInfo;
+    DWORD DriveParamBlock;
+    WORD FirstCluster;
+    WORD FileTime;
+    WORD FileDate;
+    DWORD FileSize;
+    DWORD CurrentOffset;
+    WORD LastClusterAccessed;
+    DWORD DirEntSector;
+    BYTE DirEntryIndex;
+    CHAR FileName[11];
+    BYTE Reserved0[6];
+    WORD OwnerPsp;
+    BYTE Reserved1[8];
+} DOS_SFT_ENTRY, *PDOS_SFT_ENTRY;
+
+typedef struct _DOS_SFT
+{
+    DWORD NextTablePtr;
+    WORD FileCount;
+    DOS_SFT_ENTRY Entry[ANYSIZE_ARRAY];
+} DOS_SFT, *PDOS_SFT;
+
+typedef struct _DOS_INPUT_BUFFER
+{
+    BYTE MaxLength, Length;
+    CHAR Buffer[ANYSIZE_ARRAY];
+} DOS_INPUT_BUFFER, *PDOS_INPUT_BUFFER;
+
+#pragma pack(pop)
+
+/* FUNCTIONS ******************************************************************/
+
+extern LPVOID BaseAddress;
+extern BOOLEAN VdmRunning;
+extern LPCWSTR ExceptionName[];
+
+VOID DisplayMessage(LPCWSTR Format, ...);
+BOOLEAN BiosInitialize();
+VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress);
+VOID BiosPrintCharacter(CHAR Character, BYTE Attribute);
+BOOLEAN DosInitialize();
+WORD DosAllocateMemory(WORD Size);
+BOOLEAN DosFreeMemory(WORD Segment);
+WORD DosResizeMemory(WORD Segment, WORD NewSize);
+BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock);
+VOID DosInt20h(WORD CodeSegment);
+VOID DosInt21h(WORD CodeSegment);
+VOID DosBreakInterrupt();
+VOID BiosVideoService();
+VOID EmulatorSetStack(WORD Segment, WORD Offset);
+VOID EmulatorExecute(WORD Segment, WORD Offset);
+VOID EmulatorInterrupt(BYTE Number);
+ULONG EmulatorGetRegister(ULONG Register);
+VOID EmulatorSetRegister(ULONG Register, ULONG Value);
+VOID EmulatorSetFlag(ULONG Flag);
+VOID EmulatorClearFlag(ULONG Flag);
+BOOLEAN EmulatorGetFlag(ULONG Flag);
+BOOLEAN EmulatorInitialize();
+VOID EmulatorStep();
+VOID EmulatorCleanup();
+
+/* EOF */
index 7a60799..899ea9b 100644 (file)
@@ -1,8 +1,12 @@
+#include <windef.h>
+#include <winuser.h>
+#include "resource.h"
 
-#include <windows.h>
-#define REACTOS_STR_FILE_DESCRIPTION   "ReactOS Virtual DOS Machine\0"
-#define REACTOS_STR_INTERNAL_NAME      "ntvdm\0"
-#define REACTOS_STR_ORIGINAL_FILENAME  "ntvdm.exe\0"
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+#define REACTOS_STR_FILE_DESCRIPTION    "ReactOS Virtual DOS Machine"
+#define REACTOS_STR_INTERNAL_NAME       "ntvdm"
+#define REACTOS_STR_ORIGINAL_FILENAME   "ntvdm.exe"
 #include <reactos/version.rc>
 
 #include "rsrc.rc"
index 7bc342c..6b0c1d9 100644 (file)
@@ -1,6 +1,2 @@
-#define RC_STRING_MAX_SIZE                 2048
-#define STRING_WelcomeMsg                   100
-#define STRING_PromptMsg                    101
-
 
 /* EOF */
index 61433bf..97d661b 100644 (file)
@@ -1,27 +1,4 @@
-#include <windows.h>
-#include "resource.h"
-
-/* Language-specific resources */
-#include "lang/bg-BG.rc"
-#include "lang/cs-CZ.rc"
-#include "lang/de-DE.rc"
-#include "lang/en-US.rc"
-#include "lang/es-ES.rc"
-#include "lang/fr-FR.rc"
-#include "lang/hu-HU.rc"
-#include "lang/id-ID.rc"
-#include "lang/it-IT.rc"
-#include "lang/ja-JP.rc"
-#include "lang/no-NO.rc"
-#include "lang/th-TH.rc"
-#include "lang/pt-BR.rc"
-#include "lang/sk-SK.rc"
-#include "lang/zh-CN.rc"
-#include "lang/zh-TW.rc"
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 
 // UTF-8
 #pragma code_page(65001)
-#include "lang/pl-PL.rc"
-#include "lang/ro-RO.rc"
-#include "lang/ru-RU.rc"
-#include "lang/uk-UA.rc"