diff --git a/subsystems/ntvdm/CMakeLists.txt b/subsystems/ntvdm/CMakeLists.txt index 7a1c6aa155d..af24b9100b8 100644 --- a/subsystems/ntvdm/CMakeLists.txt +++ b/subsystems/ntvdm/CMakeLists.txt @@ -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 index 00000000000..1e9c5b4430e --- /dev/null +++ b/subsystems/ntvdm/bios.c @@ -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 + */ + +#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 index 00000000000..e2402bb3af3 --- /dev/null +++ b/subsystems/ntvdm/dos.c @@ -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 + */ + +#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 index 00000000000..313067c4411 --- /dev/null +++ b/subsystems/ntvdm/emulator.c @@ -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 + */ + +/* INCLUDES *******************************************************************/ + +#include "ntvdm.h" +#include +#include + +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 index 663207c7362..00000000000 --- a/subsystems/ntvdm/lang/bg-BG.rc +++ /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 , s q ." -END diff --git a/subsystems/ntvdm/lang/cs-CZ.rc b/subsystems/ntvdm/lang/cs-CZ.rc deleted file mode 100644 index 8db30d071f8..00000000000 --- a/subsystems/ntvdm/lang/cs-CZ.rc +++ /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 virtulnho DOS stroje.\n" -STRING_PromptMsg, "Napite r pro sputn, s pro vypnut nebo q pro ukonen." -END diff --git a/subsystems/ntvdm/lang/de-DE.rc b/subsystems/ntvdm/lang/de-DE.rc deleted file mode 100644 index 423a74f7fd1..00000000000 --- a/subsystems/ntvdm/lang/de-DE.rc +++ /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-Untersttzung.\n" -STRING_PromptMsg, "Drcken Sie r zum Starten, s zum Herunterfahren oder q zum Beenden." -END diff --git a/subsystems/ntvdm/lang/en-US.rc b/subsystems/ntvdm/lang/en-US.rc deleted file mode 100644 index 9f8624727b3..00000000000 --- a/subsystems/ntvdm/lang/en-US.rc +++ /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 to run, s to shutdown or q to quit now." -END diff --git a/subsystems/ntvdm/lang/es-ES.rc b/subsystems/ntvdm/lang/es-ES.rc deleted file mode 100644 index 0741393bafa..00000000000 --- a/subsystems/ntvdm/lang/es-ES.rc +++ /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 para correr, s para desactivar or q para salir ahora." -END diff --git a/subsystems/ntvdm/lang/fr-FR.rc b/subsystems/ntvdm/lang/fr-FR.rc deleted file mode 100644 index 37b86936720..00000000000 --- a/subsystems/ntvdm/lang/fr-FR.rc +++ /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 pour dmarrer, s pour teindre ou q pour quitter maintenant." -END diff --git a/subsystems/ntvdm/lang/hu-HU.rc b/subsystems/ntvdm/lang/hu-HU.rc deleted file mode 100644 index 8ca986fb82f..00000000000 --- a/subsystems/ntvdm/lang/hu-HU.rc +++ /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 Virtulis DOS Gp tmogats.\n" -STRING_PromptMsg, "Futtatshoz nyomd meg a r, lelltshoz a s vagy kilpshez a q gombot." -END diff --git a/subsystems/ntvdm/lang/id-ID.rc b/subsystems/ntvdm/lang/id-ID.rc deleted file mode 100644 index 6e6508cc551..00000000000 --- a/subsystems/ntvdm/lang/id-ID.rc +++ /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 untuk menjalankan, s untuk mematikan atau q untuk keluar sekarang." -END diff --git a/subsystems/ntvdm/lang/it-IT.rc b/subsystems/ntvdm/lang/it-IT.rc deleted file mode 100644 index 27482474a6a..00000000000 --- a/subsystems/ntvdm/lang/it-IT.rc +++ /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 per avviare, s per arrestare o q per abbandonare ora." -END diff --git a/subsystems/ntvdm/lang/ja-JP.rc b/subsystems/ntvdm/lang/ja-JP.rc deleted file mode 100644 index aaacec4699f..00000000000 --- a/subsystems/ntvdm/lang/ja-JP.rc +++ /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, "Nɂ r AVbg_Eɂ s AIɂ q ͂ĂB" -END diff --git a/subsystems/ntvdm/lang/no-NO.rc b/subsystems/ntvdm/lang/no-NO.rc deleted file mode 100644 index fded50c397b..00000000000 --- a/subsystems/ntvdm/lang/no-NO.rc +++ /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 sttte.\n" -STRING_PromptMsg, "Skriv r for kjre, s avslutte eller q for slutte n." -END diff --git a/subsystems/ntvdm/lang/pl-PL.rc b/subsystems/ntvdm/lang/pl-PL.rc deleted file mode 100644 index 30c3186d441..00000000000 --- a/subsystems/ntvdm/lang/pl-PL.rc +++ /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 aby uruchomić, s aby wyłączyć lub q, aby zakończyć." -END diff --git a/subsystems/ntvdm/lang/pt-BR.rc b/subsystems/ntvdm/lang/pt-BR.rc deleted file mode 100644 index 0c256c72971..00000000000 --- a/subsystems/ntvdm/lang/pt-BR.rc +++ /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 para executar, s para desligar ou q para sair." -END diff --git a/subsystems/ntvdm/lang/ro-RO.rc b/subsystems/ntvdm/lang/ro-RO.rc deleted file mode 100644 index 9ec32ba9383..00000000000 --- a/subsystems/ntvdm/lang/ro-RO.rc +++ /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 pentru a executa, s pentru a închide sau q 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 index c446b86ccce..00000000000 --- a/subsystems/ntvdm/lang/ru-RU.rc +++ /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 для запуска, s для выключения или q выхода." -END diff --git a/subsystems/ntvdm/lang/sk-SK.rc b/subsystems/ntvdm/lang/sk-SK.rc deleted file mode 100644 index f510a578036..00000000000 --- a/subsystems/ntvdm/lang/sk-SK.rc +++ /dev/null @@ -1,11 +0,0 @@ -/* TRANSLATOR: Mrio Kamr /Mario Kacmar/ aka Kario (kario@szm.sk) - * DATE OF TR: 12-02-2008 - */ - -LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT -STRINGTABLE DISCARDABLE -BEGIN - -STRING_WelcomeMsg, "Podpora virtulneho DOSovho stroja v systme ReactOS.\n" -STRING_PromptMsg, "Napte r pre spustenie, s pre vypnutie alebo q pre okamit skonenie." -END diff --git a/subsystems/ntvdm/lang/th-TH.rc b/subsystems/ntvdm/lang/th-TH.rc deleted file mode 100644 index 1eea0bce494..00000000000 --- a/subsystems/ntvdm/lang/th-TH.rc +++ /dev/null @@ -1,8 +0,0 @@ - -LANGUAGE LANG_THAI, SUBLANG_DEFAULT -STRINGTABLE DISCARDABLE -BEGIN - -STRING_WelcomeMsg, "ͧѺ÷ӧҹк͹ͧ ReactOS\n" -STRING_PromptMsg, "Ẻ r ͷӧҹ, s ͻԴк q ͡ѹ" -END diff --git a/subsystems/ntvdm/lang/uk-UA.rc b/subsystems/ntvdm/lang/uk-UA.rc deleted file mode 100644 index be237589f7c..00000000000 --- a/subsystems/ntvdm/lang/uk-UA.rc +++ /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 для запуску, s для закриття або q, щоб вийти зараз." -END diff --git a/subsystems/ntvdm/lang/zh-CN.rc b/subsystems/ntvdm/lang/zh-CN.rc deleted file mode 100644 index 82b27de2611..00000000000 --- a/subsystems/ntvdm/lang/zh-CN.rc +++ /dev/null @@ -1,8 +0,0 @@ - -LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED -STRINGTABLE DISCARDABLE -BEGIN - -STRING_WelcomeMsg, "ReactOS DOS ֧֡\n" -STRING_PromptMsg, " r ԱУs Աرջ q Ա˳" -END diff --git a/subsystems/ntvdm/lang/zh-TW.rc b/subsystems/ntvdm/lang/zh-TW.rc deleted file mode 100644 index fc1ad4b0b78..00000000000 --- a/subsystems/ntvdm/lang/zh-TW.rc +++ /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 HKBA s HKΪ q HKߧYhXC" -END diff --git a/subsystems/ntvdm/ntvdm.c b/subsystems/ntvdm/ntvdm.c index 29cf5734bd2..40a5cddfd83 100644 --- a/subsystems/ntvdm/ntvdm.c +++ b/subsystems/ntvdm/ntvdm.c @@ -1,375 +1,130 @@ /* - * 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 */ -/* INCLUDES *****************************************************************/ +#include "ntvdm.h" -#include -#define WIN32_NO_STATUS -#include -#include -#include -#include -#include - -#include "resource.h" - -#define NDEBUG -#include - -/* GLOBALS ******************************************************************/ - - -/* FUNCTIONS *****************************************************************/ - -void PrintString(char* fmt,...) +BOOLEAN VdmRunning = TRUE; +LPVOID BaseAddress = NULL; +LPCWSTR ExceptionName[] = { - char buffer[512]; - va_list ap; + 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" +}; - va_start(ap, fmt); - vsprintf(buffer, fmt, ap); - va_end(ap); +VOID DisplayMessage(LPCWSTR Format, ...) +{ + WCHAR Buffer[256]; + va_list Parameters; - OutputDebugStringA(buffer); + va_start(Parameters, Format); + _vsnwprintf(Buffer, 256, Format, Parameters); + MessageBox(NULL, Buffer, L"NTVDM Subsystem", MB_OK); + va_end(Parameters); } -/* -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) +BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType) { - 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) -{ - BOOL result = TRUE; - - return result; -} - -BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm) -{ - 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? + switch (ControlType) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + { + /* Perform interrupt 0x23 */ + EmulatorInterrupt(0x23); } - if (dwError == ERROR_ALREADY_EXISTS) { - // read the line entries and cache in some struct... + default: + { + /* Stop the VDM if the user logs out or closes the console */ + VdmRunning = FALSE; } - 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; - } - - } - - 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; + INT i; + BOOLEAN PrintUsage = TRUE; + CHAR CommandLine[128]; - if (vdm->ImageMem != NULL) { - if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) { - DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap); - result = FALSE; - } - vdm->ImageMem = NULL; - } - if (vdm->hHeap != NULL) { - if (!HeapDestroy(vdm->hHeap)) { - DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap); - result = FALSE; - } - vdm->hHeap = NULL; - } - return result; -} + /* Set the handler routine */ + SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); -int WINAPI -WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) -{ - VDM_CONTROL_BLOCK VdmCB; - DWORD Result; - ULONG i; - BOOL vdmStarted = FALSE; + /* Parse the command line arguments */ + for (i = 1; i < argc; i++) + { + if (argv[i][0] != L'-' && argv[i][0] != L'/') continue; - WCHAR WelcomeMsg[RC_STRING_MAX_SIZE]; - WCHAR PromptMsg[RC_STRING_MAX_SIZE]; - CHAR InputBuffer[255]; + 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); - LoadStringW( GetModuleHandle(NULL), STRING_WelcomeMsg, WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0])); - LoadStringW( GetModuleHandle(NULL), STRING_PromptMsg, PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0])); - - AllocConsole(); - SetConsoleTitleW(L"ntvdm"); - - WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), - WelcomeMsg, lstrlenW(WelcomeMsg), // wcslen(WelcomeMsg), - &Result, NULL); - - if (!CreateVDM(&VdmCB)) { - DPRINT("VDM: failed to create VDM.\n"); - //SetLastError(); - return 2; - } - - ReadConfigForVDM(&VdmCB); - - if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) { - DPRINT("VDM: failed to load configuration drivers.\n"); - //SetLastError(); - return 2; - } - if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) { - DPRINT("VDM: failed to set configuration options.\n"); - //SetLastError(); - return 3; - } - - GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH); - strcat(VdmCB.CommandLine, "\\hello.exe"); - GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH); - - for (;;) { - WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), - PromptMsg, lstrlenW(PromptMsg), // wcslen(PromptMsg), - &Result, NULL); - i = 0; - do { - ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), - &InputBuffer[i], 1, - &Result, NULL); - if (++i >= (sizeof(InputBuffer) - 1)) { + /* This is the only mandatory parameter */ + PrintUsage = FALSE; + } 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"); + default: + { + wprintf(L"Unknown option: %s", argv[i]); } } - 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; - } } - if (!ShutdownVDM(&VdmCB)) { - DPRINT("VDM: failed to cleanly shutdown VDM.\n"); - //SetLastError(); - return 5; + if (PrintUsage) + { + wprintf(L"ReactOS Virtual DOS Machine\n\n"); + wprintf(L"Usage: NTVDM /F \n"); + return 0; } - if (!DestroyVDM(&VdmCB)) { - DPRINT("VDM: failed to cleanly destroy VDM.\n"); - //SetLastError(); - return 6; + if (!EmulatorInitialize()) return 1; + + /* Initialize the system BIOS */ + if (!BiosInitialize()) + { + wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n"); + goto Cleanup; } - ExitProcess(0); + /* Initialize the VDM DOS kernel */ + if (!DosInitialize()) + { + wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n"); + goto Cleanup; + } + + /* Start the process from the command line */ + if (!DosCreateProcess(CommandLine, 0)) + { + DisplayMessage(L"Could not start program: %S", CommandLine); + return -1; + } + + /* Main loop */ + while (VdmRunning) EmulatorStep(); + +Cleanup: + EmulatorCleanup(); + return 0; } + +/* EOF */ diff --git a/subsystems/ntvdm/ntvdm.h b/subsystems/ntvdm/ntvdm.h new file mode 100644 index 00000000000..b3bfe5066a5 --- /dev/null +++ b/subsystems/ntvdm/ntvdm.h @@ -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 + */ + +/* INCLUDES *******************************************************************/ + +#include +#include +#include +#include +#include +#include + +/* 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 */ diff --git a/subsystems/ntvdm/ntvdm.rc b/subsystems/ntvdm/ntvdm.rc index 7a60799929e..899ea9b788e 100644 --- a/subsystems/ntvdm/ntvdm.rc +++ b/subsystems/ntvdm/ntvdm.rc @@ -1,8 +1,12 @@ +#include +#include +#include "resource.h" -#include -#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 #include "rsrc.rc" diff --git a/subsystems/ntvdm/resource.h b/subsystems/ntvdm/resource.h index 7bc342c2438..6b0c1d910f8 100644 --- a/subsystems/ntvdm/resource.h +++ b/subsystems/ntvdm/resource.h @@ -1,6 +1,2 @@ -#define RC_STRING_MAX_SIZE 2048 -#define STRING_WelcomeMsg 100 -#define STRING_PromptMsg 101 - /* EOF */ diff --git a/subsystems/ntvdm/rsrc.rc b/subsystems/ntvdm/rsrc.rc index 61433bf165c..97d661b69da 100644 --- a/subsystems/ntvdm/rsrc.rc +++ b/subsystems/ntvdm/rsrc.rc @@ -1,27 +1,4 @@ -#include -#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"