From 988c4490a896b2fc193798d496ab5aac5ae65f7e Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Wed, 3 Jul 2013 23:38:51 +0000 Subject: [PATCH] [NTVDM] Fix bugs in video memory access emulation. Implement several missing INT 10h functions. Resize the console screen buffer on startup. svn path=/branches/ntvdm/; revision=59421 --- subsystems/ntvdm/bios.c | 147 +++++++++++++++++++++++++----------- subsystems/ntvdm/bios.h | 2 + subsystems/ntvdm/dos.c | 1 + subsystems/ntvdm/emulator.c | 4 +- subsystems/ntvdm/emulator.h | 4 +- 5 files changed, 109 insertions(+), 49 deletions(-) diff --git a/subsystems/ntvdm/bios.c b/subsystems/ntvdm/bios.c index 1270be26844..518ebcb962c 100644 --- a/subsystems/ntvdm/bios.c +++ b/subsystems/ntvdm/bios.c @@ -16,8 +16,6 @@ /* PRIVATE VARIABLES **********************************************************/ -static BYTE CursorRow, CursorCol; -static WORD ConsoleWidth, ConsoleHeight; static BYTE BiosKeyboardMap[256]; static WORD BiosKbdBuffer[BIOS_KBD_BUFFER_SIZE]; static UINT BiosKbdBufferStart = 0, BiosKbdBufferEnd = 0; @@ -30,17 +28,9 @@ static BOOLEAN BiosPassedMidnight = FALSE; 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(FALSE); - return Result; - } - Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % ConsoleInfo.dwSize.X; - Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / ConsoleInfo.dwSize.X; + Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % CONSOLE_WIDTH; + Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / CONSOLE_WIDTH; return Result; } @@ -92,9 +82,9 @@ BOOLEAN BiosInitialize() { INT i; WORD Offset = 0; + COORD Size = { CONSOLE_WIDTH, CONSOLE_HEIGHT}; HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE); 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)); @@ -122,17 +112,8 @@ BOOLEAN BiosInitialize() 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; + /* Set the console buffer size */ + if (!SetConsoleScreenBufferSize(ConsoleOutput, Size)) return FALSE; /* Set the console input mode */ SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); @@ -168,34 +149,31 @@ VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress) { ULONG i; COORD Coordinates; - DWORD CharsWritten; + COORD Origin = { 0, 0 }; + COORD UnitSize = { 1, 1 }; + CHAR_INFO Character; + SMALL_RECT Rect; HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); + /* Start from the character address */ + StartAddress &= ~1; + /* Loop through all the addresses */ - for (i = StartAddress; i < EndAddress; i++) + for (i = StartAddress; i < EndAddress; i += 2) { /* 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); - } + /* Fill the rectangle structure */ + Rect.Left = Coordinates.X; + Rect.Top = Coordinates.Y; + + /* Fill the character data */ + Character.Char.AsciiChar = *((PCHAR)((ULONG_PTR)BaseAddress + i)); + Character.Attributes = *((PBYTE)((ULONG_PTR)BaseAddress + i + 1)); + + /* Write the character */ + WriteConsoleOutputA(ConsoleOutput, &Character, UnitSize, Origin, &Rect); } } @@ -294,6 +272,7 @@ VOID BiosVideoService() BOOLEAN Invisible = FALSE; COORD Position; CONSOLE_CURSOR_INFO CursorInfo; + CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo; CHAR_INFO Character; SMALL_RECT Rect; DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX); @@ -330,6 +309,27 @@ VOID BiosVideoService() break; } + /* Get Cursor Position */ + case 0x03: + { + INT StartLine; + + /* Retrieve the data */ + GetConsoleCursorInfo(ConsoleOutput, &CursorInfo); + GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo); + + /* Find the first line */ + StartLine = 32 - ((CursorInfo.dwSize * 32) / 100); + + /* Return the result */ + EmulatorSetRegister(EMULATOR_REG_AX, 0); + EmulatorSetRegister(EMULATOR_REG_CX, (StartLine << 8) | 0x1F); + EmulatorSetRegister(EMULATOR_REG_DX, + LOWORD(ScreenBufferInfo.dwCursorPosition.Y) << 8 + || LOWORD(ScreenBufferInfo.dwCursorPosition.X)); + break; + } + /* Scroll Up/Down Window */ case 0x06: case 0x07: @@ -355,18 +355,75 @@ VOID BiosVideoService() /* Read Character And Attribute At Cursor Position */ case 0x08: { + COORD BufferSize = { 1, 1 }, Origin = { 0, 0 }; + + /* Get the cursor position */ + GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo); + + /* Read at cursor position */ + Rect.Left = ScreenBufferInfo.dwCursorPosition.X; + Rect.Top = ScreenBufferInfo.dwCursorPosition.Y; + + /* Read the console output */ + ReadConsoleOutput(ConsoleOutput, &Character, BufferSize, Origin, &Rect); + + /* Return the result */ + EmulatorSetRegister(EMULATOR_REG_AX, + (LOBYTE(Character.Attributes) << 8) + | Character.Char.AsciiChar); + break; } /* Write Character And Attribute At Cursor Position */ case 0x09: { + DWORD CharsWritten; + + /* Get the cursor position */ + GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo); + + /* Write the attribute to the output */ + FillConsoleOutputAttribute(ConsoleOutput, + LOBYTE(Ebx), + LOWORD(Ecx), + ScreenBufferInfo.dwCursorPosition, + &CharsWritten); + + /* Write the character to the output */ + FillConsoleOutputCharacterA(ConsoleOutput, + LOBYTE(Eax), + LOWORD(Ecx), + ScreenBufferInfo.dwCursorPosition, + &CharsWritten); + break; } /* Write Character Only At Cursor Position */ case 0x0A: { + DWORD CharsWritten; + + /* Get the cursor position */ + GetConsoleScreenBufferInfo(ConsoleOutput, &ScreenBufferInfo); + + /* Write the character to the output */ + FillConsoleOutputCharacterA(ConsoleOutput, + LOBYTE(Eax), + LOWORD(Ecx), + ScreenBufferInfo.dwCursorPosition, + &CharsWritten); + + break; + } + + case 0x0F: + { + /* Return just text mode information, for now */ + EmulatorSetRegister(EMULATOR_REG_AX, 0x5003); + EmulatorSetRegister(EMULATOR_REG_BX, 0x0000); + break; } diff --git a/subsystems/ntvdm/bios.h b/subsystems/ntvdm/bios.h index 54fbdf66ae8..0e4e49927bd 100644 --- a/subsystems/ntvdm/bios.h +++ b/subsystems/ntvdm/bios.h @@ -26,6 +26,8 @@ #define BIOS_EQUIPMENT_INTERRUPT 0x11 #define BIOS_KBD_INTERRUPT 0x16 #define BIOS_TIME_INTERRUPT 0x1A +#define CONSOLE_WIDTH 80 +#define CONSOLE_HEIGHT 25 #define CONSOLE_FONT_HEIGHT 8 #define BIOS_KBD_BUFFER_SIZE 256 #define BIOS_EQUIPMENT_LIST 0x3C // HACK: Disable FPU for now diff --git a/subsystems/ntvdm/dos.c b/subsystems/ntvdm/dos.c index 71ec4d724f7..a78c63c3bcf 100644 --- a/subsystems/ntvdm/dos.c +++ b/subsystems/ntvdm/dos.c @@ -943,6 +943,7 @@ VOID DosInt21h(WORD CodeSegment) } /* Read Character Without Echo */ + case 0x07: case 0x08: { EmulatorSetRegister(EMULATOR_REG_AX, diff --git a/subsystems/ntvdm/emulator.c b/subsystems/ntvdm/emulator.c index 7c7513bbf09..e5b22fea206 100644 --- a/subsystems/ntvdm/emulator.c +++ b/subsystems/ntvdm/emulator.c @@ -36,8 +36,8 @@ static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT S && (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)); + BiosUpdateVideoMemory(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 */ diff --git a/subsystems/ntvdm/emulator.h b/subsystems/ntvdm/emulator.h index b8eb9c1b7d1..8a24d3ae763 100644 --- a/subsystems/ntvdm/emulator.h +++ b/subsystems/ntvdm/emulator.h @@ -47,7 +47,7 @@ enum EMULATOR_EXCEPTION_NO_FPU }; -typedef enum +enum { EMULATOR_REG_AX, EMULATOR_REG_CX, @@ -61,7 +61,7 @@ typedef enum EMULATOR_REG_CS, EMULATOR_REG_SS, EMULATOR_REG_DS, -} EMULATOR_REGISTER; +}; /* FUNCTIONS ******************************************************************/ -- 2.17.1