[NTVDM]
[reactos.git] / subsystems / ntvdm / bios.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: bios.c
5 * PURPOSE: VDM BIOS
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 #include "ntvdm.h"
10
11 BYTE CursorRow, CursorCol;
12 WORD ConsoleWidth, ConsoleHeight;
13
14 BOOLEAN BiosInitialize()
15 {
16 INT i;
17 WORD Offset = 0;
18 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
19 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
20 LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress);
21 LPBYTE BiosCode = (LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(BIOS_SEGMENT, 0));
22
23 /* Generate ISR stubs and fill the IVT */
24 for (i = 0; i < 256; i++)
25 {
26 IntVecTable[i * 2] = Offset;
27 IntVecTable[i * 2 + 1] = BIOS_SEGMENT;
28
29 if (i != SPECIAL_INT_NUM)
30 {
31 BiosCode[Offset++] = 0xFA; // cli
32
33 BiosCode[Offset++] = 0x6A; // push i
34 BiosCode[Offset++] = (BYTE)i;
35
36 BiosCode[Offset++] = 0xCD; // int SPECIAL_INT_NUM
37 BiosCode[Offset++] = SPECIAL_INT_NUM;
38
39 BiosCode[Offset++] = 0x83; // add sp, 2
40 BiosCode[Offset++] = 0xC4;
41 BiosCode[Offset++] = 0x02;
42 }
43
44 BiosCode[Offset++] = 0xCF; // iret
45 }
46
47 /* Get the console buffer info */
48 if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
49 {
50 return FALSE;
51 }
52
53 /* Set the initial cursor position and console size */
54 CursorCol = ConsoleInfo.dwCursorPosition.X;
55 CursorRow = ConsoleInfo.dwCursorPosition.Y;
56 ConsoleWidth = ConsoleInfo.dwSize.X;
57 ConsoleHeight = ConsoleInfo.dwSize.Y;
58
59 return TRUE;
60 }
61
62 static COORD BiosVideoAddressToCoord(ULONG Address)
63 {
64 COORD Result = {0, 0};
65 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
66 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
67
68 if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
69 {
70 assert(0);
71 return Result;
72 }
73
74 Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % ConsoleInfo.dwSize.X;
75 Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / ConsoleInfo.dwSize.X;
76
77 return Result;
78 }
79
80 VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
81 {
82 ULONG i;
83 COORD Coordinates;
84 DWORD CharsWritten;
85 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
86
87 /* Loop through all the addresses */
88 for (i = StartAddress; i < EndAddress; i++)
89 {
90 /* Get the coordinates */
91 Coordinates = BiosVideoAddressToCoord(i);
92
93 /* Check if this is a character byte or an attribute byte */
94 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
95 {
96 /* This is a regular character */
97 FillConsoleOutputCharacterA(ConsoleOutput,
98 *(PCHAR)((ULONG_PTR)BaseAddress + i),
99 sizeof(CHAR),
100 Coordinates,
101 &CharsWritten);
102 }
103 else
104 {
105 /* This is an attribute */
106 FillConsoleOutputAttribute(ConsoleOutput,
107 *(PCHAR)((ULONG_PTR)BaseAddress + i),
108 sizeof(CHAR),
109 Coordinates,
110 &CharsWritten);
111 }
112 }
113 }
114
115 VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
116 {
117 ULONG i;
118 COORD Coordinates;
119 WORD Attribute;
120 DWORD CharsWritten;
121 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
122
123 /* Loop through all the addresses */
124 for (i = StartAddress; i < EndAddress; i++)
125 {
126 /* Get the coordinates */
127 Coordinates = BiosVideoAddressToCoord(i);
128
129 /* Check if this is a character byte or an attribute byte */
130 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
131 {
132 /* This is a regular character */
133 ReadConsoleOutputCharacterA(ConsoleOutput,
134 (LPSTR)((ULONG_PTR)BaseAddress + i),
135 sizeof(CHAR),
136 Coordinates,
137 &CharsWritten);
138 }
139 else
140 {
141 /* This is an attribute */
142 ReadConsoleOutputAttribute(ConsoleOutput,
143 &Attribute,
144 sizeof(CHAR),
145 Coordinates,
146 &CharsWritten);
147
148 *(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
149 }
150 }
151 }
152
153 VOID BiosVideoService()
154 {
155 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
156 INT CursorHeight;
157 BOOLEAN Invisible = FALSE;
158 COORD Position;
159 CONSOLE_CURSOR_INFO CursorInfo;
160 CHAR_INFO Character;
161 SMALL_RECT Rect;
162 DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
163 DWORD Ecx = EmulatorGetRegister(EMULATOR_REG_CX);
164 DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
165 DWORD Ebx = EmulatorGetRegister(EMULATOR_REG_BX);
166
167 switch (HIBYTE(Eax))
168 {
169 /* Set Text-Mode Cursor Shape */
170 case 0x01:
171 {
172 /* Retrieve and validate the input */
173 Invisible = ((HIBYTE(Ecx) >> 5) & 0x03) ? TRUE : FALSE;
174 CursorHeight = (HIBYTE(Ecx) & 0x1F) - (LOBYTE(Ecx) & 0x1F);
175 if (CursorHeight < 1) CursorHeight = 1;
176 if (CursorHeight > 100) CursorHeight = 100;
177
178 /* Set the cursor */
179 CursorInfo.dwSize = (CursorHeight * 100) / CONSOLE_FONT_HEIGHT;
180 CursorInfo.bVisible = !Invisible;
181 SetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
182
183 break;
184 }
185
186 /* Set Cursor Position */
187 case 0x02:
188 {
189 Position.X = LOBYTE(Edx);
190 Position.Y = HIBYTE(Edx);
191
192 SetConsoleCursorPosition(ConsoleOutput, Position);
193 break;
194 }
195
196 /* Scroll Up/Down Window */
197 case 0x06:
198 case 0x07:
199 {
200 Rect.Top = HIBYTE(Ecx);
201 Rect.Left = LOBYTE(Ecx);
202 Rect.Bottom = HIBYTE(Edx);
203 Rect.Right = LOBYTE(Edx);
204 Character.Char.UnicodeChar = L' ';
205 Character.Attributes = HIBYTE(Ebx);
206 Position.X = Rect.Left;
207 if (HIBYTE(Eax) == 0x06) Position.Y = Rect.Top - LOBYTE(Eax);
208 else Position.Y = Rect.Top + LOBYTE(Eax);
209
210 ScrollConsoleScreenBuffer(ConsoleOutput,
211 &Rect,
212 &Rect,
213 Position,
214 &Character);
215 break;
216 }
217
218 /* Read Character And Attribute At Cursor Position */
219 case 0x08:
220 {
221 break;
222 }
223
224 /* Write Character And Attribute At Cursor Position */
225 case 0x09:
226 {
227 break;
228 }
229
230 /* Write Character Only At Cursor Position */
231 case 0x0A:
232 {
233 break;
234 }
235 }
236 }
237
238 /* EOF */