From 425717c4835fab8147bfeffb7d8992598467e117 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 5 Jan 2014 21:26:33 +0000 Subject: [PATCH] [NTVDM] - Move console text buffer copy into VGA memory, to the BIOS (function BiosCopyTextConsoleToVgaMemory), and do it just after the BIOS sets its default display mode. - Try to resize "correctly" the console to its original size when cleaning BIOS (Part 2/2, see revision 61538). Still WIP. - Code cleaning in vga.c svn path=/branches/ntvdm/; revision=61542 --- subsystems/ntvdm/bios.c | 1387 +++++++++++++++++++++------------------ subsystems/ntvdm/bios.h | 23 +- subsystems/ntvdm/vga.c | 100 +-- 3 files changed, 759 insertions(+), 751 deletions(-) diff --git a/subsystems/ntvdm/bios.c b/subsystems/ntvdm/bios.c index ef3a0b11e7d..d3cec8f0c31 100644 --- a/subsystems/ntvdm/bios.c +++ b/subsystems/ntvdm/bios.c @@ -264,9 +264,9 @@ static PVGA_REGISTERS VideoModes[BIOS_MAX_VIDEO_MODE + 1] = &VideoMode_40x25_text, /* Mode 01h */ // 16 color &VideoMode_80x25_text, /* Mode 02h */ // 16 color (mono) &VideoMode_80x25_text, /* Mode 03h */ // 16 color - &VideoMode_320x200_4color, /* Mode 04h */ // 4 color - &VideoMode_320x200_4color, /* Mode 05h */ // same (m) - &VideoMode_640x200_2color, /* Mode 06h */ // 640*200 2 color + &VideoMode_320x200_4color, /* Mode 04h */ // CGA 4 color + &VideoMode_320x200_4color, /* Mode 05h */ // CGA same (m) + &VideoMode_640x200_2color, /* Mode 06h */ // CGA 640*200 2 color NULL, /* Mode 07h */ // MDA monochrome text 80*25 NULL, /* Mode 08h */ // PCjr NULL, /* Mode 09h */ // PCjr @@ -710,6 +710,138 @@ static VOID BiosWriteWindow(LPWORD Buffer, SMALL_RECT Rectangle, BYTE Page) } } +static BOOLEAN BiosScrollWindow(INT Direction, + DWORD Amount, + SMALL_RECT Rectangle, + BYTE Page, + BYTE FillAttribute) +{ + DWORD i; + LPWORD WindowData; + WORD WindowWidth = Rectangle.Right - Rectangle.Left + 1; + WORD WindowHeight = Rectangle.Bottom - Rectangle.Top + 1; + DWORD WindowSize = WindowWidth * WindowHeight; + + /* Allocate a buffer for the window */ + WindowData = (LPWORD)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + WindowSize * sizeof(WORD)); + if (WindowData == NULL) return FALSE; + + /* Read the window data */ + BiosReadWindow(WindowData, Rectangle, Page); + + if ((Amount == 0) + || (((Direction == SCROLL_DIRECTION_UP) + || (Direction == SCROLL_DIRECTION_DOWN)) + && (Amount >= WindowHeight)) + || (((Direction == SCROLL_DIRECTION_LEFT) + || (Direction == SCROLL_DIRECTION_RIGHT)) + && (Amount >= WindowWidth))) + { + /* Fill the window */ + for (i = 0; i < WindowSize; i++) + { + WindowData[i] = MAKEWORD(' ', FillAttribute); + } + + goto Done; + } + + switch (Direction) + { + case SCROLL_DIRECTION_UP: + { + RtlMoveMemory(WindowData, + &WindowData[WindowWidth * Amount], + (WindowSize - WindowWidth * Amount) * sizeof(WORD)); + + for (i = 0; i < Amount * WindowWidth; i++) + { + WindowData[WindowSize - i - 1] = MAKEWORD(' ', FillAttribute); + } + + break; + } + + case SCROLL_DIRECTION_DOWN: + { + RtlMoveMemory(&WindowData[WindowWidth * Amount], + WindowData, + (WindowSize - WindowWidth * Amount) * sizeof(WORD)); + + for (i = 0; i < Amount * WindowWidth; i++) + { + WindowData[i] = MAKEWORD(' ', FillAttribute); + } + + break; + } + + default: + { + // TODO: NOT IMPLEMENTED! + UNIMPLEMENTED; + } + } + +Done: + /* Write back the window data */ + BiosWriteWindow(WindowData, Rectangle, Page); + + /* Free the window buffer */ + HeapFree(GetProcessHeap(), 0, WindowData); + + return TRUE; +} + +static VOID BiosCopyTextConsoleToVgaMemory(VOID) +{ + PCHAR_INFO CharBuffer; + COORD BufferSize = {Bda->ScreenColumns, Bda->ScreenRows + 1}; + COORD Origin = { 0, 0 }; + SMALL_RECT ScreenRect; + + INT i, j; + INT Counter = 0; + WORD Character; + DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize); + + /* Allocate a temporary buffer for ReadConsoleOutput */ + CharBuffer = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + BufferSize.X * BufferSize.Y + * sizeof(CHAR_INFO)); + if (CharBuffer == NULL) return; + + ScreenRect.Left = ScreenRect.Top = 0; + ScreenRect.Right = BufferSize.X; + ScreenRect.Bottom = BufferSize.Y; + + /* Read the data from the console into the temporary buffer... */ + ReadConsoleOutputA(BiosConsoleOutput, + CharBuffer, + BufferSize, + Origin, + &ScreenRect); + + /* ... and copy the temporary buffer into the VGA memory */ + for (i = 0; i < BufferSize.Y; i++) + { + for (j = 0; j < BufferSize.X; j++) + { + Character = MAKEWORD(CharBuffer[Counter].Char.AsciiChar, + (BYTE)CharBuffer[Counter].Attributes); + ++Counter; + + /* Write to video memory */ + VgaWriteMemory(VideoAddress + (i * Bda->ScreenColumns + j) * sizeof(WORD), + (LPVOID)&Character, + sizeof(WORD)); + } + } +} + static BOOLEAN VgaSetRegisters(PVGA_REGISTERS Registers) { INT i; @@ -850,14 +982,43 @@ static VOID VgaChangePalette(BYTE ModeNumber) VgaSetPalette(Palette, Size); } -/* PUBLIC FUNCTIONS ***********************************************************/ +static VOID BiosGetCursorPosition(PBYTE Row, PBYTE Column, BYTE Page) +{ + /* Make sure the selected video page is valid */ + if (Page >= BIOS_MAX_PAGES) return; + + /* Get the cursor location */ + *Row = HIBYTE(Bda->CursorPosition[Page]); + *Column = LOBYTE(Bda->CursorPosition[Page]); +} + +static VOID BiosSetCursorPosition(BYTE Row, BYTE Column, BYTE Page) +{ + /* Make sure the selected video page is valid */ + if (Page >= BIOS_MAX_PAGES) return; + + /* Update the position in the BDA */ + Bda->CursorPosition[Page] = MAKEWORD(Column, Row); + + /* Check if this is the current video page */ + if (Page == Bda->VideoPage) + { + WORD Offset = Row * Bda->ScreenColumns + Column; + + /* Modify the CRTC registers */ + VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_LOW_REG); + VgaWritePort(VGA_CRTC_DATA , LOBYTE(Offset)); + VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_HIGH_REG); + VgaWritePort(VGA_CRTC_DATA , HIBYTE(Offset)); + } +} BYTE BiosGetVideoMode(VOID) { return Bda->VideoMode; } -BOOLEAN BiosSetVideoMode(BYTE ModeNumber) +static BOOLEAN BiosSetVideoMode(BYTE ModeNumber) { BYTE Page; @@ -870,6 +1031,14 @@ BOOLEAN BiosSetVideoMode(BYTE ModeNumber) VgaChangePalette(ModeNumber); + /* + * IBM standard modes do not clear the screen if the + * high bit of AL is set (EGA or higher only). + * See Ralf Brown: http://www.ctyme.com/intr/rb-0069.htm + * for more information. + */ + if ((ModeNumber & 0x08) == 0) VgaClearMemory(); + // Bda->CrtModeControl; // Bda->CrtColorPaletteMask; // Bda->EGAFlags; @@ -895,14 +1064,14 @@ BOOLEAN BiosSetVideoMode(BYTE ModeNumber) Bda->ScreenColumns = Resolution.X; Bda->ScreenRows = Resolution.Y - 1; - /* Set cursor position for each page */ + /* Set the cursor position for each page */ for (Page = 0; Page < BIOS_MAX_PAGES; ++Page) BiosSetCursorPosition(0, 0, Page); return TRUE; } -BOOLEAN BiosSetVideoPage(BYTE PageNumber) +static BOOLEAN BiosSetVideoPage(BYTE PageNumber) { BYTE Row, Column; @@ -932,455 +1101,70 @@ BOOLEAN BiosSetVideoPage(BYTE PageNumber) return TRUE; } -BOOLEAN BiosInitialize(VOID) +static VOID WINAPI BiosVideoService(LPWORD Stack) { - /* Initialize the BDA */ - Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0); - Bda->EquipmentList = BIOS_EQUIPMENT_LIST; - /* - * Conventional memory size is 640 kB, - * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM - * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm - * for more information. - */ - Bda->MemorySize = 0x0280; - Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer); - Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD); - Bda->KeybdBufferHead = Bda->KeybdBufferTail = 0; - - /* Initialize the 32-bit Interrupt system */ - InitializeInt32(BIOS_SEGMENT); + switch (getAH()) + { + /* Set Video Mode */ + case 0x00: + { + BiosSetVideoMode(getAL()); + break; + } - /* Register the BIOS 32-bit Interrupts */ - RegisterInt32(BIOS_VIDEO_INTERRUPT , BiosVideoService ); - RegisterInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService ); - RegisterInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize ); - RegisterInt32(BIOS_MISC_INTERRUPT , BiosMiscService ); - RegisterInt32(BIOS_KBD_INTERRUPT , BiosKeyboardService ); - RegisterInt32(BIOS_TIME_INTERRUPT , BiosTimeService ); - RegisterInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt); + /* Set Text-Mode Cursor Shape */ + case 0x01: + { + /* Update the BDA */ + Bda->CursorStartLine = getCH(); + Bda->CursorEndLine = getCL(); - /* Some interrupts are in fact addresses to tables */ - ((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL; + /* Modify the CRTC registers */ + VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_START_REG); + VgaWritePort(VGA_CRTC_DATA , Bda->CursorStartLine); + VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_END_REG); + VgaWritePort(VGA_CRTC_DATA , Bda->CursorEndLine); - ((PDWORD)BaseAddress)[0x41] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x43] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x44] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x46] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x48] = (DWORD)NULL; - ((PDWORD)BaseAddress)[0x49] = (DWORD)NULL; + break; + } - /* Get the input handle to the real console, and check for success */ - BiosConsoleInput = CreateFileW(L"CONIN$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - 0, - NULL); - if (BiosConsoleInput == INVALID_HANDLE_VALUE) - { - return FALSE; - } + /* Set Cursor Position */ + case 0x02: + { + BiosSetCursorPosition(getDH(), getDL(), getBH()); + break; + } - /* Get the output handle to the real console, and check for success */ - BiosConsoleOutput = CreateFileW(L"CONOUT$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - 0, - NULL); - if (BiosConsoleOutput == INVALID_HANDLE_VALUE) - { - CloseHandle(BiosConsoleInput); - return FALSE; - } + /* Get Cursor Position */ + case 0x03: + { + /* Make sure the selected video page exists */ + if (getBH() >= BIOS_MAX_PAGES) break; - /* Save the console screen buffer information */ - if (!GetConsoleScreenBufferInfo(BiosConsoleOutput, &BiosSavedBufferInfo)) - { - CloseHandle(BiosConsoleOutput); - CloseHandle(BiosConsoleInput); - return FALSE; - } + /* Return the result */ + setAX(0); + setCX(MAKEWORD(Bda->CursorEndLine, Bda->CursorStartLine)); + setDX(Bda->CursorPosition[getBH()]); + break; + } - /* Initialize VGA */ - if (!VgaInitialize(BiosConsoleOutput)) - { - CloseHandle(BiosConsoleOutput); - CloseHandle(BiosConsoleInput); - return FALSE; - } + /* Query Light Pen */ + case 0x04: + { + /* + * On modern BIOSes, this function returns 0 + * so that we can ignore the other registers. + */ + setAX(0); + break; + } - /* Update the cursor position */ - BiosSetCursorPosition(BiosSavedBufferInfo.dwCursorPosition.Y, - BiosSavedBufferInfo.dwCursorPosition.X, - 0); - - /* Set the console input mode */ - SetConsoleMode(BiosConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); - - /* Initialize PS2 */ - PS2Initialize(BiosConsoleInput); - - /* Initialize the PIC */ - PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4); - PicWriteCommand(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4); - - /* Set the interrupt offsets */ - PicWriteData(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT); - PicWriteData(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT); - - /* Tell the master PIC there is a slave at IRQ 2 */ - PicWriteData(PIC_MASTER_DATA, 1 << 2); - PicWriteData(PIC_SLAVE_DATA , 2); - - /* Make sure the PIC is in 8086 mode */ - PicWriteData(PIC_MASTER_DATA, PIC_ICW4_8086); - PicWriteData(PIC_SLAVE_DATA , PIC_ICW4_8086); - - /* Clear the masks for both PICs */ - PicWriteData(PIC_MASTER_DATA, 0x00); - PicWriteData(PIC_SLAVE_DATA , 0x00); - - PitWriteCommand(0x34); - PitWriteData(0, 0x00); - PitWriteData(0, 0x00); - - return TRUE; -} - -VOID BiosCleanup(VOID) -{ - PS2Cleanup(); - - /* Restore the old screen buffer */ - SetConsoleActiveScreenBuffer(BiosConsoleOutput); - - /* Restore the screen buffer size */ - SetConsoleScreenBufferSize(BiosConsoleOutput, BiosSavedBufferInfo.dwSize); - - /* Close the console handles */ - if (BiosConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleOutput); - if (BiosConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleInput); -} - -WORD BiosPeekCharacter(VOID) -{ - WORD CharacterData = 0; - - /* Get the key from the queue, but don't remove it */ - if (BiosKbdBufferTop(&CharacterData)) return CharacterData; - else return 0xFFFF; -} - -WORD BiosGetCharacter(VOID) -{ - WORD CharacterData = 0; - - /* Check if there is a key available */ - if (BiosKbdBufferTop(&CharacterData)) - { - /* A key was available, remove it from the queue */ - BiosKbdBufferPop(); - } - else - { - /* No key available. Set the handler CF to repeat the BOP */ - setCF(1); - // CharacterData = 0xFFFF; - } - - return CharacterData; -} - -VOID BiosGetCursorPosition(PBYTE Row, PBYTE Column, BYTE Page) -{ - /* Make sure the selected video page is valid */ - if (Page >= BIOS_MAX_PAGES) return; - - /* Get the cursor location */ - *Row = HIBYTE(Bda->CursorPosition[Page]); - *Column = LOBYTE(Bda->CursorPosition[Page]); -} - -VOID BiosSetCursorPosition(BYTE Row, BYTE Column, BYTE Page) -{ - /* Make sure the selected video page is valid */ - if (Page >= BIOS_MAX_PAGES) return; - - /* Update the position in the BDA */ - Bda->CursorPosition[Page] = MAKEWORD(Column, Row); - - /* Check if this is the current video page */ - if (Page == Bda->VideoPage) - { - WORD Offset = Row * Bda->ScreenColumns + Column; - - /* Modify the CRTC registers */ - VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_LOW_REG); - VgaWritePort(VGA_CRTC_DATA , LOBYTE(Offset)); - VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_HIGH_REG); - VgaWritePort(VGA_CRTC_DATA , HIBYTE(Offset)); - } -} - -BOOLEAN BiosScrollWindow(INT Direction, - DWORD Amount, - SMALL_RECT Rectangle, - BYTE Page, - BYTE FillAttribute) -{ - DWORD i; - LPWORD WindowData; - WORD WindowWidth = Rectangle.Right - Rectangle.Left + 1; - WORD WindowHeight = Rectangle.Bottom - Rectangle.Top + 1; - DWORD WindowSize = WindowWidth * WindowHeight; - - /* Allocate a buffer for the window */ - WindowData = (LPWORD)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - WindowSize * sizeof(WORD)); - if (WindowData == NULL) return FALSE; - - /* Read the window data */ - BiosReadWindow(WindowData, Rectangle, Page); - - if ((Amount == 0) - || (((Direction == SCROLL_DIRECTION_UP) - || (Direction == SCROLL_DIRECTION_DOWN)) - && (Amount >= WindowHeight)) - || (((Direction == SCROLL_DIRECTION_LEFT) - || (Direction == SCROLL_DIRECTION_RIGHT)) - && (Amount >= WindowWidth))) - { - /* Fill the window */ - for (i = 0; i < WindowSize; i++) - { - WindowData[i] = MAKEWORD(' ', FillAttribute); - } - - goto Done; - } - - switch (Direction) - { - case SCROLL_DIRECTION_UP: - { - RtlMoveMemory(WindowData, - &WindowData[WindowWidth * Amount], - (WindowSize - WindowWidth * Amount) * sizeof(WORD)); - - for (i = 0; i < Amount * WindowWidth; i++) - { - WindowData[WindowSize - i - 1] = MAKEWORD(' ', FillAttribute); - } - - break; - } - - case SCROLL_DIRECTION_DOWN: - { - RtlMoveMemory(&WindowData[WindowWidth * Amount], - WindowData, - (WindowSize - WindowWidth * Amount) * sizeof(WORD)); - - for (i = 0; i < Amount * WindowWidth; i++) - { - WindowData[i] = MAKEWORD(' ', FillAttribute); - } - - break; - } - - default: - { - // TODO: NOT IMPLEMENTED! - UNIMPLEMENTED; - } - } - -Done: - /* Write back the window data */ - BiosWriteWindow(WindowData, Rectangle, Page); - - /* Free the window buffer */ - HeapFree(GetProcessHeap(), 0, WindowData); - - return TRUE; -} - -VOID BiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page) -{ - WORD CharData = MAKEWORD(Character, Attribute); - BYTE Row, Column; - - /* Make sure the page exists */ - if (Page >= BIOS_MAX_PAGES) return; - - /* Get the cursor location */ - BiosGetCursorPosition(&Row, &Column, Page); - - if (Character == '\a') - { - /* Bell control character */ - // NOTE: We may use what the terminal emulator offers to us... - Beep(800, 200); - return; - } - else if (Character == '\b') - { - /* Backspace control character */ - if (Column > 0) - { - Column--; - } - else if (Row > 0) - { - Column = Bda->ScreenColumns - 1; - Row--; - } - - /* Erase the existing character */ - CharData = MAKEWORD(' ', Attribute); - EmulatorWriteMemory(&EmulatorContext, - TO_LINEAR(TEXT_VIDEO_SEG, - Page * Bda->VideoPageSize + - (Row * Bda->ScreenColumns + Column) * sizeof(WORD)), - (LPVOID)&CharData, - sizeof(WORD)); - } - else if (Character == '\t') - { - /* Horizontal Tabulation control character */ - do - { - // Taken from DOSBox - BiosPrintCharacter(' ', Attribute, Page); - BiosGetCursorPosition(&Row, &Column, Page); - } while (Column % 8); - } - else if (Character == '\n') - { - /* Line Feed control character */ - Row++; - } - else if (Character == '\r') - { - /* Carriage Return control character */ - Column = 0; - } - else - { - /* Default character */ - - /* Write the character */ - EmulatorWriteMemory(&EmulatorContext, - TO_LINEAR(TEXT_VIDEO_SEG, - Page * Bda->VideoPageSize + - (Row * Bda->ScreenColumns + Column) * sizeof(WORD)), - (LPVOID)&CharData, - sizeof(WORD)); - - /* Advance the cursor */ - Column++; - } - - /* Check if it passed the end of the row */ - if (Column >= Bda->ScreenColumns) - { - /* Return to the first column and go to the next line */ - Column = 0; - Row++; - } - - /* Scroll the screen up if needed */ - if (Row > Bda->ScreenRows) - { - /* The screen must be scrolled up */ - SMALL_RECT Rectangle = { 0, 0, Bda->ScreenColumns - 1, Bda->ScreenRows }; - - BiosScrollWindow(SCROLL_DIRECTION_UP, - 1, - Rectangle, - Page, - DEFAULT_ATTRIBUTE); - - Row--; - } - - /* Set the cursor position */ - BiosSetCursorPosition(Row, Column, Page); -} - -VOID WINAPI BiosVideoService(LPWORD Stack) -{ - switch (getAH()) - { - /* Set Video Mode */ - case 0x00: - { - BiosSetVideoMode(getAL()); - VgaClearMemory(); - break; - } - - /* Set Text-Mode Cursor Shape */ - case 0x01: - { - /* Update the BDA */ - Bda->CursorStartLine = getCH(); - Bda->CursorEndLine = getCL(); - - /* Modify the CRTC registers */ - VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_START_REG); - VgaWritePort(VGA_CRTC_DATA , Bda->CursorStartLine); - VgaWritePort(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_END_REG); - VgaWritePort(VGA_CRTC_DATA , Bda->CursorEndLine); - - break; - } - - /* Set Cursor Position */ - case 0x02: - { - BiosSetCursorPosition(getDH(), getDL(), getBH()); - break; - } - - /* Get Cursor Position */ - case 0x03: - { - /* Make sure the selected video page exists */ - if (getBH() >= BIOS_MAX_PAGES) break; - - /* Return the result */ - setAX(0); - setCX(MAKEWORD(Bda->CursorEndLine, Bda->CursorStartLine)); - setDX(Bda->CursorPosition[getBH()]); - break; - } - - /* Query Light Pen */ - case 0x04: - { - /* - * On modern BIOSes, this function returns 0 - * so that we can ignore the other registers. - */ - setAX(0); - break; - } - - /* Select Active Display Page */ - case 0x05: - { - BiosSetVideoPage(getAL()); - break; - } + /* Select Active Display Page */ + case 0x05: + { + BiosSetVideoPage(getAL()); + break; + } /* Scroll Window Up/Down */ case 0x06: @@ -1622,274 +1406,567 @@ VOID WINAPI BiosVideoService(LPWORD Stack) setCH(VgaReadPort(VGA_DAC_DATA)); setCL(VgaReadPort(VGA_DAC_DATA)); - break; - } + break; + } + + /* Get Block of DAC Registers */ + case 0x17: + { + INT i; + LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX()); + + /* Write the index */ + // Certainly in BL and not in BX as said by Ralf Brown... + VgaWritePort(VGA_DAC_READ_INDEX, getBL()); + + for (i = 0; i < getCX(); i++) + { + /* Write the data in this order: Red, Green, Blue */ + *Buffer++ = VgaReadPort(VGA_DAC_DATA); + *Buffer++ = VgaReadPort(VGA_DAC_DATA); + *Buffer++ = VgaReadPort(VGA_DAC_DATA); + } + + break; + } + + default: + { + DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n", + getAL()); + break; + } + } + + break; + } + + /* Scroll Window */ + case 0x12: + { + SMALL_RECT Rectangle = { getCL(), getCH(), getDL(), getDH() }; + + /* Call the internal function */ + BiosScrollWindow(getBL(), + getAL(), + Rectangle, + Bda->VideoPage, + DEFAULT_ATTRIBUTE); + + break; + } + + /* Display combination code */ + case 0x1A: + { + switch(getAL()) + { + case 0x00: /* Get Display combiantion code */ + setAX(MAKEWORD(0x1A, 0x1A)); + setBX(MAKEWORD(0x08, 0x00)); /* VGA w/ color analog display */ + break; + case 0x01: /* Set Display combination code */ + DPRINT1("Set Display combination code - Unsupported\n"); + break; + default: + break; + } + break; + } + + default: + { + DPRINT1("BIOS Function INT 10h, AH = 0x%02X NOT IMPLEMENTED\n", + getAH()); + } + } +} + +static VOID WINAPI BiosEquipmentService(LPWORD Stack) +{ + /* Return the equipment list */ + setAX(Bda->EquipmentList); +} + +static VOID WINAPI BiosGetMemorySize(LPWORD Stack) +{ + /* Return the conventional memory size in kB, typically 640 kB */ + setAX(Bda->MemorySize); +} + +static VOID WINAPI BiosMiscService(LPWORD Stack) +{ + switch (getAH()) + { + /* Copy Extended Memory */ + case 0x87: + { + DWORD Count = (DWORD)getCX() * 2; + PFAST486_GDT_ENTRY Gdt = (PFAST486_GDT_ENTRY)SEG_OFF_TO_PTR(getES(), getSI()); + DWORD SourceBase = Gdt[2].Base + (Gdt[2].BaseMid << 16) + (Gdt[2].BaseHigh << 24); + DWORD SourceLimit = Gdt[2].Limit + (Gdt[2].LimitHigh << 16); + DWORD DestBase = Gdt[3].Base + (Gdt[3].BaseMid << 16) + (Gdt[3].BaseHigh << 24); + DWORD DestLimit = Gdt[3].Limit + (Gdt[3].LimitHigh << 16); + + /* Check for flags */ + if (Gdt[2].Granularity) SourceLimit = (SourceLimit << 12) | 0xFFF; + if (Gdt[3].Granularity) DestLimit = (DestLimit << 12) | 0xFFF; + + if ((Count > SourceLimit) || (Count > DestLimit)) + { + setAX(0x80); + Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + + break; + } + + /* Copy */ + RtlMoveMemory((PVOID)((ULONG_PTR)BaseAddress + DestBase), + (PVOID)((ULONG_PTR)BaseAddress + SourceBase), + Count); + + setAX(ERROR_SUCCESS); + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + break; + } + + /* Get Extended Memory Size */ + case 0x88: + { + /* Return the number of KB of RAM after 1 MB */ + setAX((MAX_ADDRESS - 0x100000) / 1024); + + /* Clear CF */ + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + + break; + } + + default: + { + DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n", + getAH()); + } + } +} + +static VOID WINAPI BiosKeyboardService(LPWORD Stack) +{ + switch (getAH()) + { + /* Wait for keystroke and read */ + case 0x00: + /* Wait for extended keystroke and read */ + case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h + { + /* Read the character (and wait if necessary) */ + setAX(BiosGetCharacter()); + break; + } + + /* Get keystroke status */ + case 0x01: + /* Get extended keystroke status */ + case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h + { + WORD Data = BiosPeekCharacter(); + + if (Data != 0xFFFF) + { + /* There is a character, clear ZF and return it */ + Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF; + setAX(Data); + } + else + { + /* No character, set ZF */ + Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF; + } - /* Get Block of DAC Registers */ - case 0x17: - { - INT i; - LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX()); + break; + } - /* Write the index */ - // Certainly in BL and not in BX as said by Ralf Brown... - VgaWritePort(VGA_DAC_READ_INDEX, getBL()); + /* Get shift status */ + case 0x02: + { + /* Return the lower byte of the keyboard shift status word */ + setAL(LOBYTE(Bda->KeybdShiftFlags)); + break; + } - for (i = 0; i < getCX(); i++) - { - /* Write the data in this order: Red, Green, Blue */ - *Buffer++ = VgaReadPort(VGA_DAC_DATA); - *Buffer++ = VgaReadPort(VGA_DAC_DATA); - *Buffer++ = VgaReadPort(VGA_DAC_DATA); - } + /* Reserved */ + case 0x04: + { + DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n"); + break; + } - break; - } + /* Push keystroke */ + case 0x05: + { + /* Return 0 if success, 1 if failure */ + setAL(BiosKbdBufferPush(getCX()) == FALSE); + break; + } - default: - { - DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n", - getAL()); - break; - } - } + /* Get extended shift status */ + case 0x12: + { + /* + * Be careful! The returned word is similar to Bda->KeybdShiftFlags + * but the high byte is organized differently: + * the bytes 2 and 3 of the high byte are not the same... + */ + WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF); + /* Return the extended keyboard shift status word */ + setAX(KeybdShiftFlags); break; } - /* Scroll Window */ - case 0x12: + default: { - SMALL_RECT Rectangle = { getCL(), getCH(), getDL(), getDH() }; + DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n", + getAH()); + } + } +} - /* Call the internal function */ - BiosScrollWindow(getBL(), - getAL(), - Rectangle, - Bda->VideoPage, - DEFAULT_ATTRIBUTE); +static VOID WINAPI BiosTimeService(LPWORD Stack) +{ + switch (getAH()) + { + case 0x00: + { + /* Set AL to 1 if midnight had passed, 0 otherwise */ + setAL(Bda->MidnightPassed ? 0x01 : 0x00); + + /* Return the tick count in CX:DX */ + setCX(HIWORD(Bda->TickCounter)); + setDX(LOWORD(Bda->TickCounter)); + + /* Reset the midnight flag */ + Bda->MidnightPassed = FALSE; break; } - /* Display combination code */ - case 0x1A: + case 0x01: { - switch(getAL()) - { - case 0x00: /* Get Display combiantion code */ - setAX(MAKEWORD(0x1A, 0x1A)); - setBX(MAKEWORD(0x08, 0x00)); /* VGA w/ color analog display */ - break; - case 0x01: /* Set Display combination code */ - DPRINT1("Set Display combination code - Unsupported\n"); - break; - default: - break; - } + /* Set the tick count to CX:DX */ + Bda->TickCounter = MAKELONG(getDX(), getCX()); + + /* Reset the midnight flag */ + Bda->MidnightPassed = FALSE; + break; } default: { - DPRINT1("BIOS Function INT 10h, AH = 0x%02X NOT IMPLEMENTED\n", + DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n", getAH()); } } } -VOID WINAPI BiosEquipmentService(LPWORD Stack) +static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack) { - /* Return the equipment list */ - setAX(Bda->EquipmentList); + /* Increase the system tick count */ + Bda->TickCounter++; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +WORD BiosPeekCharacter(VOID) +{ + WORD CharacterData = 0; + + /* Get the key from the queue, but don't remove it */ + if (BiosKbdBufferTop(&CharacterData)) return CharacterData; + else return 0xFFFF; +} + +WORD BiosGetCharacter(VOID) +{ + WORD CharacterData = 0; + + /* Check if there is a key available */ + if (BiosKbdBufferTop(&CharacterData)) + { + /* A key was available, remove it from the queue */ + BiosKbdBufferPop(); + } + else + { + /* No key available. Set the handler CF to repeat the BOP */ + setCF(1); + // CharacterData = 0xFFFF; + } + + return CharacterData; } -VOID WINAPI BiosGetMemorySize(LPWORD Stack) -{ - /* Return the conventional memory size in kB, typically 640 kB */ - setAX(Bda->MemorySize); +VOID BiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page) +{ + WORD CharData = MAKEWORD(Character, Attribute); + BYTE Row, Column; + + /* Make sure the page exists */ + if (Page >= BIOS_MAX_PAGES) return; + + /* Get the cursor location */ + BiosGetCursorPosition(&Row, &Column, Page); + + if (Character == '\a') + { + /* Bell control character */ + // NOTE: We may use what the terminal emulator offers to us... + Beep(800, 200); + return; + } + else if (Character == '\b') + { + /* Backspace control character */ + if (Column > 0) + { + Column--; + } + else if (Row > 0) + { + Column = Bda->ScreenColumns - 1; + Row--; + } + + /* Erase the existing character */ + CharData = MAKEWORD(' ', Attribute); + EmulatorWriteMemory(&EmulatorContext, + TO_LINEAR(TEXT_VIDEO_SEG, + Page * Bda->VideoPageSize + + (Row * Bda->ScreenColumns + Column) * sizeof(WORD)), + (LPVOID)&CharData, + sizeof(WORD)); + } + else if (Character == '\t') + { + /* Horizontal Tabulation control character */ + do + { + // Taken from DOSBox + BiosPrintCharacter(' ', Attribute, Page); + BiosGetCursorPosition(&Row, &Column, Page); + } while (Column % 8); + } + else if (Character == '\n') + { + /* Line Feed control character */ + Row++; + } + else if (Character == '\r') + { + /* Carriage Return control character */ + Column = 0; + } + else + { + /* Default character */ + + /* Write the character */ + EmulatorWriteMemory(&EmulatorContext, + TO_LINEAR(TEXT_VIDEO_SEG, + Page * Bda->VideoPageSize + + (Row * Bda->ScreenColumns + Column) * sizeof(WORD)), + (LPVOID)&CharData, + sizeof(WORD)); + + /* Advance the cursor */ + Column++; + } + + /* Check if it passed the end of the row */ + if (Column >= Bda->ScreenColumns) + { + /* Return to the first column and go to the next line */ + Column = 0; + Row++; + } + + /* Scroll the screen up if needed */ + if (Row > Bda->ScreenRows) + { + /* The screen must be scrolled up */ + SMALL_RECT Rectangle = { 0, 0, Bda->ScreenColumns - 1, Bda->ScreenRows }; + + BiosScrollWindow(SCROLL_DIRECTION_UP, + 1, + Rectangle, + Page, + DEFAULT_ATTRIBUTE); + + Row--; + } + + /* Set the cursor position */ + BiosSetCursorPosition(Row, Column, Page); } -VOID WINAPI BiosMiscService(LPWORD Stack) +BOOLEAN BiosInitialize(VOID) { - switch (getAH()) - { - /* Copy Extended Memory */ - case 0x87: - { - DWORD Count = (DWORD)getCX() * 2; - PFAST486_GDT_ENTRY Gdt = (PFAST486_GDT_ENTRY)SEG_OFF_TO_PTR(getES(), getSI()); - DWORD SourceBase = Gdt[2].Base + (Gdt[2].BaseMid << 16) + (Gdt[2].BaseHigh << 24); - DWORD SourceLimit = Gdt[2].Limit + (Gdt[2].LimitHigh << 16); - DWORD DestBase = Gdt[3].Base + (Gdt[3].BaseMid << 16) + (Gdt[3].BaseHigh << 24); - DWORD DestLimit = Gdt[3].Limit + (Gdt[3].LimitHigh << 16); - - /* Check for flags */ - if (Gdt[2].Granularity) SourceLimit = (SourceLimit << 12) | 0xFFF; - if (Gdt[3].Granularity) DestLimit = (DestLimit << 12) | 0xFFF; - - if ((Count > SourceLimit) || (Count > DestLimit)) - { - setAX(0x80); - Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; - break; - } + /* Initialize the BDA */ + Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0); + Bda->EquipmentList = BIOS_EQUIPMENT_LIST; + /* + * Conventional memory size is 640 kB, + * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM + * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm + * for more information. + */ + Bda->MemorySize = 0x0280; + Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer); + Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD); + Bda->KeybdBufferHead = Bda->KeybdBufferTail = 0; - /* Copy */ - RtlMoveMemory((PVOID)((ULONG_PTR)BaseAddress + DestBase), - (PVOID)((ULONG_PTR)BaseAddress + SourceBase), - Count); + /* Initialize the 32-bit Interrupt system */ + InitializeInt32(BIOS_SEGMENT); - setAX(ERROR_SUCCESS); - Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; - break; - } + /* Register the BIOS 32-bit Interrupts */ + RegisterInt32(BIOS_VIDEO_INTERRUPT , BiosVideoService ); + RegisterInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService ); + RegisterInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize ); + RegisterInt32(BIOS_MISC_INTERRUPT , BiosMiscService ); + RegisterInt32(BIOS_KBD_INTERRUPT , BiosKeyboardService ); + RegisterInt32(BIOS_TIME_INTERRUPT , BiosTimeService ); + RegisterInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt); - /* Get Extended Memory Size */ - case 0x88: - { - /* Return the number of KB of RAM after 1 MB */ - setAX((MAX_ADDRESS - 0x100000) / 1024); + /* Some interrupts are in fact addresses to tables */ + ((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL; - /* Clear CF */ - Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; + ((PDWORD)BaseAddress)[0x41] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x43] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x44] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x46] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x48] = (DWORD)NULL; + ((PDWORD)BaseAddress)[0x49] = (DWORD)NULL; - break; - } + /* Get the input handle to the real console, and check for success */ + BiosConsoleInput = CreateFileW(L"CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (BiosConsoleInput == INVALID_HANDLE_VALUE) + { + return FALSE; + } - default: - { - DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n", - getAH()); - } + /* Get the output handle to the real console, and check for success */ + BiosConsoleOutput = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (BiosConsoleOutput == INVALID_HANDLE_VALUE) + { + CloseHandle(BiosConsoleInput); + return FALSE; } -} -VOID WINAPI BiosKeyboardService(LPWORD Stack) -{ - switch (getAH()) + /* Save the original console screen buffer information */ + if (!GetConsoleScreenBufferInfo(BiosConsoleOutput, &BiosSavedBufferInfo)) { - /* Wait for keystroke and read */ - case 0x00: - /* Wait for extended keystroke and read */ - case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h - { - /* Read the character (and wait if necessary) */ - setAX(BiosGetCharacter()); - break; - } + CloseHandle(BiosConsoleOutput); + CloseHandle(BiosConsoleInput); + return FALSE; + } - /* Get keystroke status */ - case 0x01: - /* Get extended keystroke status */ - case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h - { - WORD Data = BiosPeekCharacter(); + /* Initialize VGA */ + if (!VgaInitialize(BiosConsoleOutput)) + { + CloseHandle(BiosConsoleOutput); + CloseHandle(BiosConsoleInput); + return FALSE; + } - if (Data != 0xFFFF) - { - /* There is a character, clear ZF and return it */ - Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF; - setAX(Data); - } - else - { - /* No character, set ZF */ - Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF; - } + /* Set the default video mode */ + BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE); - break; - } + /* Copy console data into VGA memory */ + BiosCopyTextConsoleToVgaMemory(); - /* Get shift status */ - case 0x02: - { - /* Return the lower byte of the keyboard shift status word */ - setAL(LOBYTE(Bda->KeybdShiftFlags)); - break; - } + /* Update the cursor position for the current page (page 0) */ + GetConsoleScreenBufferInfo(BiosConsoleOutput, &ConsoleInfo); + BiosSetCursorPosition(ConsoleInfo.dwCursorPosition.Y, + ConsoleInfo.dwCursorPosition.X, + Bda->VideoPage); - /* Reserved */ - case 0x04: - { - DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n"); - break; - } + /* Set the console input mode */ + SetConsoleMode(BiosConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT); - /* Push keystroke */ - case 0x05: - { - /* Return 0 if success, 1 if failure */ - setAL(BiosKbdBufferPush(getCX()) == FALSE); - break; - } + /* Initialize PS2 */ + PS2Initialize(BiosConsoleInput); - /* Get extended shift status */ - case 0x12: - { - /* - * Be careful! The returned word is similar to Bda->KeybdShiftFlags - * but the high byte is organized differently: - * the bytes 2 and 3 of the high byte are not the same... - */ - WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF); + /* Initialize the PIC */ + PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4); + PicWriteCommand(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4); - /* Return the extended keyboard shift status word */ - setAX(KeybdShiftFlags); - break; - } + /* Set the interrupt offsets */ + PicWriteData(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT); + PicWriteData(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT); - default: - { - DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n", - getAH()); - } - } -} + /* Tell the master PIC there is a slave at IRQ 2 */ + PicWriteData(PIC_MASTER_DATA, 1 << 2); + PicWriteData(PIC_SLAVE_DATA , 2); -VOID WINAPI BiosTimeService(LPWORD Stack) -{ - switch (getAH()) - { - case 0x00: - { - /* Set AL to 1 if midnight had passed, 0 otherwise */ - setAL(Bda->MidnightPassed ? 0x01 : 0x00); + /* Make sure the PIC is in 8086 mode */ + PicWriteData(PIC_MASTER_DATA, PIC_ICW4_8086); + PicWriteData(PIC_SLAVE_DATA , PIC_ICW4_8086); - /* Return the tick count in CX:DX */ - setCX(HIWORD(Bda->TickCounter)); - setDX(LOWORD(Bda->TickCounter)); + /* Clear the masks for both PICs */ + PicWriteData(PIC_MASTER_DATA, 0x00); + PicWriteData(PIC_SLAVE_DATA , 0x00); - /* Reset the midnight flag */ - Bda->MidnightPassed = FALSE; + PitWriteCommand(0x34); + PitWriteData(0, 0x00); + PitWriteData(0, 0x00); - break; - } + return TRUE; +} - case 0x01: - { - /* Set the tick count to CX:DX */ - Bda->TickCounter = MAKELONG(getDX(), getCX()); +VOID BiosCleanup(VOID) +{ + SMALL_RECT ConRect; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; - /* Reset the midnight flag */ - Bda->MidnightPassed = FALSE; + PS2Cleanup(); - break; - } + /* Restore the old screen buffer */ + SetConsoleActiveScreenBuffer(BiosConsoleOutput); - default: - { - DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n", - getAH()); - } - } -} + /* Restore the original console size */ + GetConsoleScreenBufferInfo(BiosConsoleOutput, &ConsoleInfo); + ConRect.Left = 0; // BiosSavedBufferInfo.srWindow.Left; + // ConRect.Top = ConsoleInfo.dwCursorPosition.Y / (BiosSavedBufferInfo.srWindow.Bottom - BiosSavedBufferInfo.srWindow.Top + 1); + // ConRect.Top *= (BiosSavedBufferInfo.srWindow.Bottom - BiosSavedBufferInfo.srWindow.Top + 1); + ConRect.Top = ConsoleInfo.dwCursorPosition.Y; + ConRect.Right = ConRect.Left + BiosSavedBufferInfo.srWindow.Right - BiosSavedBufferInfo.srWindow.Left; + ConRect.Bottom = ConRect.Top + (BiosSavedBufferInfo.srWindow.Bottom - BiosSavedBufferInfo.srWindow.Top); + /* See the following trick explanation in vga.c:VgaEnterTextMode() */ + SetConsoleScreenBufferSize(BiosConsoleOutput, BiosSavedBufferInfo.dwSize); + SetConsoleWindowInfo(BiosConsoleOutput, TRUE, &ConRect); + // SetConsoleWindowInfo(BiosConsoleOutput, TRUE, &BiosSavedBufferInfo.srWindow); + SetConsoleScreenBufferSize(BiosConsoleOutput, BiosSavedBufferInfo.dwSize); -VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack) -{ - /* Increase the system tick count */ - Bda->TickCounter++; + /* Close the console handles */ + if (BiosConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleOutput); + if (BiosConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleInput); } VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack) diff --git a/subsystems/ntvdm/bios.h b/subsystems/ntvdm/bios.h index 836d015b0c2..acc5a175b60 100644 --- a/subsystems/ntvdm/bios.h +++ b/subsystems/ntvdm/bios.h @@ -151,31 +151,12 @@ C_ASSERT(sizeof(BIOS_DATA_AREA) == 0x133); extern PBIOS_DATA_AREA Bda; -BOOLEAN BiosInitialize(VOID); -VOID BiosCleanup(VOID); -BYTE BiosGetVideoMode(VOID); -BOOLEAN BiosSetVideoMode(BYTE ModeNumber); WORD BiosPeekCharacter(VOID); WORD BiosGetCharacter(VOID); -VOID BiosGetCursorPosition(PBYTE Row, PBYTE Column, BYTE Page); -VOID BiosSetCursorPosition(BYTE Row, BYTE Column, BYTE Page); VOID BiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page); -BOOLEAN BiosScrollWindow( - INT Direction, - DWORD Amount, - SMALL_RECT Rectangle, - BYTE Page, - BYTE FillAttribute -); - -VOID WINAPI BiosVideoService(LPWORD Stack); -VOID WINAPI BiosEquipmentService(LPWORD Stack); -VOID WINAPI BiosGetMemorySize(LPWORD Stack); -VOID WINAPI BiosMiscService(LPWORD Stack); -VOID WINAPI BiosKeyboardService(LPWORD Stack); -VOID WINAPI BiosTimeService(LPWORD Stack); -VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack); +BOOLEAN BiosInitialize(VOID); +VOID BiosCleanup(VOID); VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack); #endif // _BIOS_H_ diff --git a/subsystems/ntvdm/vga.c b/subsystems/ntvdm/vga.c index 9c429a7a7b7..7702446c9f4 100644 --- a/subsystems/ntvdm/vga.c +++ b/subsystems/ntvdm/vga.c @@ -171,8 +171,7 @@ static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] = #endif -static HANDLE VgaSavedConsoleHandle = NULL; -static CONSOLE_SCREEN_BUFFER_INFO VgaSavedConsoleInfo; +static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; static BYTE VgaMemory[VGA_NUM_BANKS * VGA_BANK_SIZE]; static LPVOID ConsoleFramebuffer = NULL; @@ -234,15 +233,16 @@ static inline DWORD VgaGetAddressSize(VOID) /* Double-word addressing */ return 4; // sizeof(DWORD) } - - if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE) + else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE) { /* Byte addressing */ return 1; // sizeof(BYTE) } - - /* Word addressing */ - return 2; // sizeof(WORD) + else + { + /* Word addressing */ + return 2; // sizeof(WORD) + } } static inline DWORD VgaTranslateReadAddress(DWORD Address) @@ -611,8 +611,8 @@ static VOID VgaLeaveGraphicsMode(VOID) /* Release the console framebuffer mutex */ ReleaseMutex(ConsoleMutex); - /* Switch back to the default console buffer */ - // SetConsoleActiveScreenBuffer(VgaSavedConsoleHandle); + /* Switch back to the default console text buffer */ + // SetConsoleActiveScreenBuffer(TextConsoleBuffer); /* Cleanup the video data */ CloseHandle(ConsoleMutex); @@ -630,8 +630,8 @@ static BOOL VgaEnterTextMode(PCOORD Resolution) SetConsoleActiveScreenBuffer(TextConsoleBuffer); /* Resize the console */ - ConRect.Left = 0; // VgaSavedConsoleInfo.srWindow.Left; - ConRect.Top = VgaSavedConsoleInfo.srWindow.Top; + ConRect.Left = 0; // ConsoleInfo.srWindow.Left; + ConRect.Top = ConsoleInfo.srWindow.Top; ConRect.Right = ConRect.Left + Resolution->X - 1; ConRect.Bottom = ConRect.Top + Resolution->Y - 1; /* @@ -646,7 +646,7 @@ static BOOL VgaEnterTextMode(PCOORD Resolution) SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect); SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution); /* Update the saved console information */ - GetConsoleScreenBufferInfo(TextConsoleBuffer, &VgaSavedConsoleInfo); + GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo); /* Allocate a framebuffer */ ConsoleFramebuffer = HeapAlloc(GetProcessHeap(), @@ -690,9 +690,6 @@ static VOID VgaChangeMode(VOID) { COORD Resolution = VgaGetDisplayResolution(); - /* Reset the mode change flag */ - // ModeChanged = FALSE; - if (ScreenMode == GRAPHICS_MODE) { /* Leave the current graphics mode */ @@ -929,7 +926,9 @@ static VOID VgaUpdateFramebuffer(VOID) else { /* Text mode */ + DWORD CurrentAddr; PCHAR_INFO CharBuffer = (PCHAR_INFO)ConsoleFramebuffer; + CHAR_INFO CharInfo; /* Loop through the scanlines */ for (i = 0; i < Resolution.Y; i++) @@ -937,8 +936,7 @@ static VOID VgaUpdateFramebuffer(VOID) /* Loop through the characters */ for (j = 0; j < Resolution.X; j++) { - DWORD CurrentAddr = LOWORD((Address + j) * AddressSize); - CHAR_INFO CharInfo; + CurrentAddr = LOWORD((Address + j) * AddressSize); /* Plane 0 holds the character itself */ CharInfo.Char.AsciiChar = VgaMemory[CurrentAddr]; @@ -976,7 +974,7 @@ static VOID VgaUpdateTextCursor(VOID) VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]); /* Just return if we are not in text mode */ - if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) != 0) return; + if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) return; if (CursorStart < CursorEnd) { @@ -1078,15 +1076,15 @@ VOID VgaRefreshDisplay(VOID) if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate) return; - /* Retrieve the current resolution */ - Resolution = VgaGetDisplayResolution(); - /* Change the display mode */ if (ModeChanged) VgaChangeMode(); /* Change the text cursor location */ if (CursorMoved) VgaUpdateTextCursor(); + /* Retrieve the current resolution */ + Resolution = VgaGetDisplayResolution(); + if (PaletteChanged) { /* Trigger a full update of the screen */ @@ -1492,21 +1490,12 @@ VOID VgaResetPalette(VOID) BOOLEAN VgaInitialize(HANDLE TextHandle) { - INT i, j; - COORD Resolution; - DWORD AddressSize; - DWORD ScanlineSize; - COORD Origin = { 0, 0 }; - SMALL_RECT ScreenRect; - PCHAR_INFO CharBuffer; - DWORD Address = 0; - DWORD CurrentAddr; + /* Save the default text-mode console output handle */ + if (TextHandle == INVALID_HANDLE_VALUE) return FALSE; + TextConsoleBuffer = TextHandle; /* Save the console information */ - if (TextHandle == INVALID_HANDLE_VALUE) return FALSE; - VgaSavedConsoleHandle = TextHandle; - if (!GetConsoleScreenBufferInfo(VgaSavedConsoleHandle, - &VgaSavedConsoleInfo)) + if (!GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo)) { return FALSE; } @@ -1515,8 +1504,8 @@ BOOLEAN VgaInitialize(HANDLE TextHandle) if (!VgaInitializePalette()) return FALSE; /***/ VgaResetPalette(); /***/ - /* Save the default text-mode console output handle */ - TextConsoleBuffer = TextHandle; + /* Switch to the text buffer */ + SetConsoleActiveScreenBuffer(TextConsoleBuffer); /* Clear the VGA memory */ VgaClearMemory(); @@ -1536,45 +1525,6 @@ BOOLEAN VgaInitialize(HANDLE TextHandle) RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA - /* Set the default video mode */ - BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE); - VgaChangeMode(); - - /* Get the data */ - Resolution = VgaGetDisplayResolution(); - CharBuffer = (PCHAR_INFO)ConsoleFramebuffer; - AddressSize = VgaGetAddressSize(); - ScreenRect.Left = ScreenRect.Top = 0; - ScreenRect.Right = Resolution.X; - ScreenRect.Bottom = Resolution.Y; - ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2; - - /* Read the data from the console into the framebuffer */ - ReadConsoleOutputA(TextConsoleBuffer, - CharBuffer, - Resolution, - Origin, - &ScreenRect); - - /* Loop through the scanlines */ - for (i = 0; i < Resolution.Y; i++) - { - /* Loop through the characters */ - for (j = 0; j < Resolution.X; j++) - { - CurrentAddr = LOWORD((Address + j) * AddressSize); - - /* Store the character in plane 0 */ - VgaMemory[CurrentAddr] = CharBuffer[i * Resolution.X + j].Char.AsciiChar; - - /* Store the attribute in plane 1 */ - VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuffer[i * Resolution.X + j].Attributes; - } - - /* Move to the next scanline */ - Address += ScanlineSize; - } - /* Return success */ return TRUE; } -- 2.17.1