88afa6d3059c4d3950933da90ef0d58b2569d54b
[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 /* INCLUDES *******************************************************************/
10
11 #include "bios.h"
12 #include "emulator.h"
13 #include "pic.h"
14 #include "timer.h"
15
16 /* PRIVATE VARIABLES **********************************************************/
17
18 static BYTE CursorRow, CursorCol;
19 static WORD ConsoleWidth, ConsoleHeight;
20
21 /* PRIVATE FUNCTIONS **********************************************************/
22
23 static COORD BiosVideoAddressToCoord(ULONG Address)
24 {
25 COORD Result = {0, 0};
26 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
27 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
28
29 if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
30 {
31 ASSERT(FALSE);
32 return Result;
33 }
34
35 Result.X = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) % ConsoleInfo.dwSize.X;
36 Result.Y = ((Address - CONSOLE_VIDEO_MEM_START) >> 1) / ConsoleInfo.dwSize.X;
37
38 return Result;
39 }
40
41 /* PUBLIC FUNCTIONS ***********************************************************/
42
43 BOOLEAN BiosInitialize()
44 {
45 INT i;
46 WORD Offset = 0;
47 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
48 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
49 LPWORD IntVecTable = (LPWORD)((ULONG_PTR)BaseAddress);
50 LPBYTE BiosCode = (LPBYTE)((ULONG_PTR)BaseAddress + TO_LINEAR(BIOS_SEGMENT, 0));
51
52 /* Generate ISR stubs and fill the IVT */
53 for (i = 0; i < 256; i++)
54 {
55 IntVecTable[i * 2] = Offset;
56 IntVecTable[i * 2 + 1] = BIOS_SEGMENT;
57
58 if (i != SPECIAL_INT_NUM)
59 {
60 BiosCode[Offset++] = 0xFA; // cli
61
62 BiosCode[Offset++] = 0x6A; // push i
63 BiosCode[Offset++] = (BYTE)i;
64
65 BiosCode[Offset++] = 0xCD; // int SPECIAL_INT_NUM
66 BiosCode[Offset++] = SPECIAL_INT_NUM;
67
68 BiosCode[Offset++] = 0x83; // add sp, 2
69 BiosCode[Offset++] = 0xC4;
70 BiosCode[Offset++] = 0x02;
71 }
72
73 BiosCode[Offset++] = 0xCF; // iret
74 }
75
76 /* Get the console buffer info */
77 if (!GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo))
78 {
79 return FALSE;
80 }
81
82 /* Set the initial cursor position and console size */
83 CursorCol = ConsoleInfo.dwCursorPosition.X;
84 CursorRow = ConsoleInfo.dwCursorPosition.Y;
85 ConsoleWidth = ConsoleInfo.dwSize.X;
86 ConsoleHeight = ConsoleInfo.dwSize.Y;
87
88 /* Initialize the PIC */
89 PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
90 PicWriteCommand(PIC_SLAVE_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
91
92 /* Set the interrupt offsets */
93 PicWriteData(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
94 PicWriteData(PIC_SLAVE_DATA, BIOS_PIC_SLAVE_INT);
95
96 /* Tell the master PIC there is a slave at IRQ 2 */
97 PicWriteData(PIC_MASTER_DATA, 1 << 2);
98 PicWriteData(PIC_SLAVE_DATA, 2);
99
100 /* Make sure the PIC is in 8086 mode */
101 PicWriteData(PIC_MASTER_DATA, PIC_ICW4_8086);
102 PicWriteData(PIC_SLAVE_DATA, PIC_ICW4_8086);
103
104 /* Clear the masks for both PICs */
105 PicWriteData(PIC_MASTER_DATA, 0x00);
106 PicWriteData(PIC_SLAVE_DATA, 0x00);
107
108 PitWriteCommand(0x34);
109 PitWriteData(0, 0x00);
110 PitWriteData(0, 0x00);
111
112 return TRUE;
113 }
114
115 VOID BiosUpdateConsole(ULONG StartAddress, ULONG EndAddress)
116 {
117 ULONG i;
118 COORD Coordinates;
119 DWORD CharsWritten;
120 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
121
122 /* Loop through all the addresses */
123 for (i = StartAddress; i < EndAddress; i++)
124 {
125 /* Get the coordinates */
126 Coordinates = BiosVideoAddressToCoord(i);
127
128 /* Check if this is a character byte or an attribute byte */
129 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
130 {
131 /* This is a regular character */
132 FillConsoleOutputCharacterA(ConsoleOutput,
133 *(PCHAR)((ULONG_PTR)BaseAddress + i),
134 sizeof(CHAR),
135 Coordinates,
136 &CharsWritten);
137 }
138 else
139 {
140 /* This is an attribute */
141 FillConsoleOutputAttribute(ConsoleOutput,
142 *(PCHAR)((ULONG_PTR)BaseAddress + i),
143 sizeof(CHAR),
144 Coordinates,
145 &CharsWritten);
146 }
147 }
148 }
149
150 VOID BiosUpdateVideoMemory(ULONG StartAddress, ULONG EndAddress)
151 {
152 ULONG i;
153 COORD Coordinates;
154 WORD Attribute;
155 DWORD CharsWritten;
156 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
157
158 /* Loop through all the addresses */
159 for (i = StartAddress; i < EndAddress; i++)
160 {
161 /* Get the coordinates */
162 Coordinates = BiosVideoAddressToCoord(i);
163
164 /* Check if this is a character byte or an attribute byte */
165 if ((i - CONSOLE_VIDEO_MEM_START) % 2 == 0)
166 {
167 /* This is a regular character */
168 ReadConsoleOutputCharacterA(ConsoleOutput,
169 (LPSTR)((ULONG_PTR)BaseAddress + i),
170 sizeof(CHAR),
171 Coordinates,
172 &CharsWritten);
173 }
174 else
175 {
176 /* This is an attribute */
177 ReadConsoleOutputAttribute(ConsoleOutput,
178 &Attribute,
179 sizeof(CHAR),
180 Coordinates,
181 &CharsWritten);
182
183 *(PCHAR)((ULONG_PTR)BaseAddress + i) = LOBYTE(Attribute);
184 }
185 }
186 }
187
188 VOID BiosVideoService()
189 {
190 HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
191 INT CursorHeight;
192 BOOLEAN Invisible = FALSE;
193 COORD Position;
194 CONSOLE_CURSOR_INFO CursorInfo;
195 CHAR_INFO Character;
196 SMALL_RECT Rect;
197 DWORD Eax = EmulatorGetRegister(EMULATOR_REG_AX);
198 DWORD Ecx = EmulatorGetRegister(EMULATOR_REG_CX);
199 DWORD Edx = EmulatorGetRegister(EMULATOR_REG_DX);
200 DWORD Ebx = EmulatorGetRegister(EMULATOR_REG_BX);
201
202 switch (HIBYTE(Eax))
203 {
204 /* Set Text-Mode Cursor Shape */
205 case 0x01:
206 {
207 /* Retrieve and validate the input */
208 Invisible = ((HIBYTE(Ecx) >> 5) & 0x03) ? TRUE : FALSE;
209 CursorHeight = (HIBYTE(Ecx) & 0x1F) - (LOBYTE(Ecx) & 0x1F);
210 if (CursorHeight < 1) CursorHeight = 1;
211 if (CursorHeight > 100) CursorHeight = 100;
212
213 /* Set the cursor */
214 CursorInfo.dwSize = (CursorHeight * 100) / CONSOLE_FONT_HEIGHT;
215 CursorInfo.bVisible = !Invisible;
216 SetConsoleCursorInfo(ConsoleOutput, &CursorInfo);
217
218 break;
219 }
220
221 /* Set Cursor Position */
222 case 0x02:
223 {
224 Position.X = LOBYTE(Edx);
225 Position.Y = HIBYTE(Edx);
226
227 SetConsoleCursorPosition(ConsoleOutput, Position);
228 break;
229 }
230
231 /* Scroll Up/Down Window */
232 case 0x06:
233 case 0x07:
234 {
235 Rect.Top = HIBYTE(Ecx);
236 Rect.Left = LOBYTE(Ecx);
237 Rect.Bottom = HIBYTE(Edx);
238 Rect.Right = LOBYTE(Edx);
239 Character.Char.UnicodeChar = L' ';
240 Character.Attributes = HIBYTE(Ebx);
241 Position.X = Rect.Left;
242 if (HIBYTE(Eax) == 0x06) Position.Y = Rect.Top - LOBYTE(Eax);
243 else Position.Y = Rect.Top + LOBYTE(Eax);
244
245 ScrollConsoleScreenBuffer(ConsoleOutput,
246 &Rect,
247 &Rect,
248 Position,
249 &Character);
250 break;
251 }
252
253 /* Read Character And Attribute At Cursor Position */
254 case 0x08:
255 {
256 break;
257 }
258
259 /* Write Character And Attribute At Cursor Position */
260 case 0x09:
261 {
262 break;
263 }
264
265 /* Write Character Only At Cursor Position */
266 case 0x0A:
267 {
268 break;
269 }
270 }
271 }
272
273 VOID BiosHandleIrq(BYTE IrqNumber)
274 {
275 PicWriteCommand(PIC_MASTER_CMD, PIC_OCW2_EOI);
276 }
277
278 /* EOF */