[NTVDM]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 5 Jan 2014 21:26:33 +0000 (21:26 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 5 Jan 2014 21:26:33 +0000 (21:26 +0000)
- 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
subsystems/ntvdm/bios.h
subsystems/ntvdm/vga.c

index ef3a0b1..d3cec8f 100644 (file)
@@ -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)
index 836d015..acc5a17 100644 (file)
@@ -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_
index 9c429a7..7702446 100644 (file)
@@ -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;
 }