- 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
This commit is contained in:
Hermès Bélusca-Maïto 2014-01-05 21:26:33 +00:00
parent 2a053222a7
commit 425717c483
3 changed files with 503 additions and 495 deletions

View 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,391 +1101,7 @@ BOOLEAN BiosSetVideoPage(BYTE PageNumber)
return TRUE;
}
BOOLEAN BiosInitialize(VOID)
{
/* 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);
/* 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);
/* Some interrupts are in fact addresses to tables */
((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL;
((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL;
((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL;
((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;
/* 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;
}
/* 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;
}
/* Save the console screen buffer information */
if (!GetConsoleScreenBufferInfo(BiosConsoleOutput, &BiosSavedBufferInfo))
{
CloseHandle(BiosConsoleOutput);
CloseHandle(BiosConsoleInput);
return FALSE;
}
/* Initialize VGA */
if (!VgaInitialize(BiosConsoleOutput))
{
CloseHandle(BiosConsoleOutput);
CloseHandle(BiosConsoleInput);
return FALSE;
}
/* 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)
static VOID WINAPI BiosVideoService(LPWORD Stack)
{
switch (getAH())
{
@ -1324,7 +1109,6 @@ VOID WINAPI BiosVideoService(LPWORD Stack)
case 0x00:
{
BiosSetVideoMode(getAL());
VgaClearMemory();
break;
}
@ -1698,19 +1482,19 @@ VOID WINAPI BiosVideoService(LPWORD Stack)
}
}
VOID WINAPI BiosEquipmentService(LPWORD Stack)
static VOID WINAPI BiosEquipmentService(LPWORD Stack)
{
/* Return the equipment list */
setAX(Bda->EquipmentList);
}
VOID WINAPI BiosGetMemorySize(LPWORD Stack)
static VOID WINAPI BiosGetMemorySize(LPWORD Stack)
{
/* Return the conventional memory size in kB, typically 640 kB */
setAX(Bda->MemorySize);
}
VOID WINAPI BiosMiscService(LPWORD Stack)
static VOID WINAPI BiosMiscService(LPWORD Stack)
{
switch (getAH())
{
@ -1766,7 +1550,7 @@ VOID WINAPI BiosMiscService(LPWORD Stack)
}
}
VOID WINAPI BiosKeyboardService(LPWORD Stack)
static VOID WINAPI BiosKeyboardService(LPWORD Stack)
{
switch (getAH())
{
@ -1848,7 +1632,7 @@ VOID WINAPI BiosKeyboardService(LPWORD Stack)
}
}
VOID WINAPI BiosTimeService(LPWORD Stack)
static VOID WINAPI BiosTimeService(LPWORD Stack)
{
switch (getAH())
{
@ -1886,12 +1670,305 @@ VOID WINAPI BiosTimeService(LPWORD Stack)
}
}
VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
{
/* 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 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);
}
BOOLEAN BiosInitialize(VOID)
{
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
/* 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);
/* 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);
/* Some interrupts are in fact addresses to tables */
((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL;
((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL;
((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL;
((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;
/* 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;
}
/* 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;
}
/* Save the original console screen buffer information */
if (!GetConsoleScreenBufferInfo(BiosConsoleOutput, &BiosSavedBufferInfo))
{
CloseHandle(BiosConsoleOutput);
CloseHandle(BiosConsoleInput);
return FALSE;
}
/* Initialize VGA */
if (!VgaInitialize(BiosConsoleOutput))
{
CloseHandle(BiosConsoleOutput);
CloseHandle(BiosConsoleInput);
return FALSE;
}
/* Set the default video mode */
BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
/* Copy console data into VGA memory */
BiosCopyTextConsoleToVgaMemory();
/* Update the cursor position for the current page (page 0) */
GetConsoleScreenBufferInfo(BiosConsoleOutput, &ConsoleInfo);
BiosSetCursorPosition(ConsoleInfo.dwCursorPosition.Y,
ConsoleInfo.dwCursorPosition.X,
Bda->VideoPage);
/* 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)
{
SMALL_RECT ConRect;
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
PS2Cleanup();
/* Restore the old screen buffer */
SetConsoleActiveScreenBuffer(BiosConsoleOutput);
/* 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);
/* Close the console handles */
if (BiosConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleOutput);
if (BiosConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleInput);
}
VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
{
switch (IrqNumber)

View 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_

View 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;
}