[NTVDM]: Start to organize the code...
[reactos.git] / subsystems / ntvdm / bios / 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 #define NDEBUG
12
13 #include "emulator.h"
14 #include "bios.h"
15
16 #include "io.h"
17 #include "hardware/vga.h"
18 #include "hardware/pic.h"
19 #include "hardware/ps2.h"
20 #include "hardware/timer.h"
21
22 #include "int32.h"
23 #include "registers.h"
24
25 /* MACROS *********************************************************************/
26
27 //
28 // These macros are defined for ease-of-use of some VGA I/O ports
29 // whose addresses depend whether we are in Monochrome or Colour mode.
30 //
31 #define VGA_INSTAT1_READ Bda->CrtBasePort + 6 // VGA_INSTAT1_READ_MONO or VGA_INSTAT1_READ_COLOR
32 #define VGA_CRTC_INDEX Bda->CrtBasePort // VGA_CRTC_INDEX_MONO or VGA_CRTC_INDEX_COLOR
33 #define VGA_CRTC_DATA Bda->CrtBasePort + 1 // VGA_CRTC_DATA_MONO or VGA_CRTC_DATA_COLOR
34
35 /* PRIVATE VARIABLES **********************************************************/
36
37 PBIOS_DATA_AREA Bda;
38 static BYTE BiosKeyboardMap[256];
39 static HANDLE BiosConsoleInput = INVALID_HANDLE_VALUE;
40 static HANDLE BiosConsoleOutput = INVALID_HANDLE_VALUE;
41 static DWORD BiosSavedConInMode, BiosSavedConOutMode;
42 static CONSOLE_CURSOR_INFO BiosSavedCursorInfo;
43 static CONSOLE_SCREEN_BUFFER_INFO BiosSavedBufferInfo;
44
45 /*
46 * VGA Register Configurations for BIOS Video Modes
47 * The configurations come from DOSBox.
48 */
49 static VGA_REGISTERS VideoMode_40x25_text =
50 {
51 /* Miscellaneous Register */
52 0x67,
53
54 /* Sequencer Registers */
55 {0x00, 0x08, 0x03, 0x00, 0x07},
56
57 /* CRTC Registers */
58 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0xA0, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
59 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x1F, 0x96, 0xB9, 0xA3,
60 0xFF},
61
62 /* GC Registers */
63 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF},
64
65 /* AC Registers */
66 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
67 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}
68 };
69
70 static VGA_REGISTERS VideoMode_80x25_text =
71 {
72 /* Miscellaneous Register */
73 0x67,
74
75 /* Sequencer Registers */
76 {0x00, 0x00, 0x03, 0x00, 0x07},
77
78 /* CRTC Registers */
79 {0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
80 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
81 0xFF},
82
83 /* GC Registers */
84 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF},
85
86 /* AC Registers */
87 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
88 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}
89 };
90
91 static VGA_REGISTERS VideoMode_320x200_4color =
92 {
93 /* Miscellaneous Register */
94 0x63,
95
96 /* Sequencer Registers */
97 {0x00, 0x09, 0x03, 0x00, 0x02},
98
99 /* CRTC Registers */
100 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xA2,
102 0xFF},
103
104 /* GC Registers */
105 {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0F, 0x0F, 0xFF},
106
107 /* AC Registers */
108 {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
109 0x14, 0x15, 0x16, 0x17, 0x01, 0x00, 0x0F, 0x00, 0x00}
110 };
111
112 static VGA_REGISTERS VideoMode_640x200_2color =
113 {
114 /* Miscellaneous Register */
115 0x63,
116
117 /* Sequencer Registers */
118 {0x00, 0x09, 0x0F, 0x00, 0x02},
119
120 /* CRTC Registers */
121 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xC2,
123 0xFF},
124
125 /* GC Registers */
126 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0xFF},
127
128 /* AC Registers */
129 {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
130 0x17, 0x17, 0x17, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00}
131 };
132
133 static VGA_REGISTERS VideoMode_320x200_16color =
134 {
135 /* Miscellaneous Register */
136 0x63,
137
138 /* Sequencer Registers */
139 {0x00, 0x09, 0x0F, 0x00, 0x02},
140
141 /* CRTC Registers */
142 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xE3,
144 0xFF},
145
146 /* GC Registers */
147 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
148
149 /* AC Registers */
150 // {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
151 // 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
152 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
153 0x14, 0x15, 0x16, 0x17, 0x01, 0x00, 0x0F, 0x00, 0x00}
154 };
155
156 static VGA_REGISTERS VideoMode_640x200_16color =
157 {
158 /* Miscellaneous Register */
159 0x63,
160
161 /* Sequencer Registers */
162 {0x00, 0x01, 0x0F, 0x00, 0x02},
163
164 /* CRTC Registers */
165 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
166 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xE3,
167 0xFF},
168
169 /* GC Registers */
170 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
171
172 /* AC Registers */
173 // {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
174 // 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
175 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
176 0x14, 0x15, 0x16, 0x17, 0x01, 0x00, 0x0F, 0x00, 0x00}
177 };
178
179 static VGA_REGISTERS VideoMode_640x350_16color =
180 {
181 /* Miscellaneous Register */
182 0xA3,
183
184 /* Sequencer Registers */
185 {0x00, 0x01, 0x0F, 0x00, 0x02},
186
187 /* CRTC Registers */
188 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x40, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x00, 0x83, 0x85, 0x5D, 0x28, 0x0F, 0x63, 0xBA, 0xE3,
190 0xFF},
191
192 /* GC Registers */
193 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
194
195 /* AC Registers */
196 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
197 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
198 };
199
200 static VGA_REGISTERS VideoMode_640x480_2color =
201 {
202 /* Miscellaneous Register */
203 0xE3,
204
205 /* Sequencer Registers */
206 {0x00, 0x01, 0x0F, 0x00, 0x02},
207
208 /* CRTC Registers */
209 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xC3,
211 0xFF},
212
213 /* GC Registers */
214 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
215
216 /* AC Registers */
217 {0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
218 0x3F, 0x3F, 0x3F, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
219 };
220
221 static VGA_REGISTERS VideoMode_640x480_16color =
222 {
223 /* Miscellaneous Register */
224 0xE3,
225
226 /* Sequencer Registers */
227 {0x00, 0x01, 0x0F, 0x00, 0x02},
228
229 /* CRTC Registers */
230 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3,
232 0xFF},
233
234 /* GC Registers */
235 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
236
237 /* AC Registers */
238 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
239 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
240 };
241
242 static VGA_REGISTERS VideoMode_320x200_256color =
243 {
244 /* Miscellaneous Register */
245 0x63,
246
247 /* Sequencer Registers */
248 {0x00, 0x01, 0x0F, 0x00, 0x0E},
249
250 /* CRTC Registers */
251 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
253 0xFF},
254
255 /* GC Registers */
256 {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF},
257
258 /* AC Registers */
259 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
260 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00}
261 };
262
263 /* See http://wiki.osdev.org/Drawing_In_Protected_Mode#Locating_Video_Memory */
264 static PVGA_REGISTERS VideoModes[BIOS_MAX_VIDEO_MODE + 1] =
265 {
266 &VideoMode_40x25_text, /* Mode 00h */ // 16 color (mono)
267 &VideoMode_40x25_text, /* Mode 01h */ // 16 color
268 &VideoMode_80x25_text, /* Mode 02h */ // 16 color (mono)
269 &VideoMode_80x25_text, /* Mode 03h */ // 16 color
270 &VideoMode_320x200_4color, /* Mode 04h */ // CGA 4 color
271 &VideoMode_320x200_4color, /* Mode 05h */ // CGA same (m)
272 &VideoMode_640x200_2color, /* Mode 06h */ // CGA 640*200 2 color
273 NULL, /* Mode 07h */ // MDA monochrome text 80*25
274 NULL, /* Mode 08h */ // PCjr
275 NULL, /* Mode 09h */ // PCjr
276 NULL, /* Mode 0Ah */ // PCjr
277 NULL, /* Mode 0Bh */ // Reserved
278 NULL, /* Mode 0Ch */ // Reserved
279 &VideoMode_320x200_16color, /* Mode 0Dh */ // EGA 320*200 16 color
280 &VideoMode_640x200_16color, /* Mode 0Eh */ // EGA 640*200 16 color
281 NULL, /* Mode 0Fh */ // EGA 640*350 mono
282 &VideoMode_640x350_16color, /* Mode 10h */ // EGA 640*350 HiRes 16 color
283 &VideoMode_640x480_2color, /* Mode 11h */ // VGA 640*480 mono
284 &VideoMode_640x480_16color, /* Mode 12h */ // VGA
285 &VideoMode_320x200_256color, /* Mode 13h */ // VGA
286 };
287
288 // FIXME: Are they computable with the previous data ??
289 // Values taken from DOSBox.
290 static WORD VideoModePageSize[BIOS_MAX_VIDEO_MODE + 1] =
291 {
292 0x0800, 0x0800, 0x1000, 0x1000,
293 0x4000, 0x4000, 0x4000, 0x1000,
294 0x0000, 0x0000, 0x0000, 0x0000,
295 0x0000, 0x2000, 0x4000, 0x8000,
296 0x8000, 0xA000, 0xA000, 0x2000
297 };
298
299 /*
300 * BIOS Mode Palettes
301 *
302 * Many people have different versions of those palettes
303 * (e.g. DOSBox, http://www.brokenthorn.com/Resources/OSDevVid2.html ,
304 * etc...) A choice should be made at some point.
305 */
306
307 // This is the same as EgaPalette__HiRes
308 static CONST COLORREF TextPalette[VGA_MAX_COLORS / 4] =
309 {
310 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
311 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0xAA, 0x00), RGB(0xAA, 0xAA, 0xAA),
312 RGB(0x00, 0x00, 0x55), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xAA, 0x55), RGB(0x00, 0xAA, 0xFF),
313 RGB(0xAA, 0x00, 0x55), RGB(0xAA, 0x00, 0xFF), RGB(0xAA, 0xAA, 0x55), RGB(0xAA, 0xAA, 0xFF),
314
315 RGB(0x00, 0x55, 0x00), RGB(0x00, 0x55, 0xAA), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xAA),
316 RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0x55, 0xAA), RGB(0xAA, 0xFF, 0x00), RGB(0xAA, 0xFF, 0xAA),
317 RGB(0x00, 0x55, 0x55), RGB(0x00, 0x55, 0xFF), RGB(0x00, 0xFF, 0x55), RGB(0x00, 0xFF, 0xFF),
318 RGB(0xAA, 0x55, 0x55), RGB(0xAA, 0x55, 0xFF), RGB(0xAA, 0xFF, 0x55), RGB(0xAA, 0xFF, 0xFF),
319
320
321 RGB(0x55, 0x00, 0x00), RGB(0x55, 0x00, 0xAA), RGB(0x55, 0xAA, 0x00), RGB(0x55, 0xAA, 0xAA),
322 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xAA), RGB(0xFF, 0xAA, 0x00), RGB(0xFF, 0xAA, 0xAA),
323 RGB(0x55, 0x00, 0x55), RGB(0x55, 0x00, 0xFF), RGB(0x55, 0xAA, 0x55), RGB(0x55, 0xAA, 0xFF),
324 RGB(0xFF, 0x00, 0x55), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xAA, 0x55), RGB(0xFF, 0xAA, 0xFF),
325
326 RGB(0x55, 0x55, 0x00), RGB(0x55, 0x55, 0xAA), RGB(0x55, 0xFF, 0x00), RGB(0x55, 0xFF, 0xAA),
327 RGB(0xFF, 0x55, 0x00), RGB(0xFF, 0x55, 0xAA), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xAA),
328 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
329 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF)
330 };
331
332 // Unused at the moment
333 static CONST COLORREF mtext_palette[64] =
334 {
335 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
336 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
337 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
338 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
339 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
340 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
341 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF),
342 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF),
343
344 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
345 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
346 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
347 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
348 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
349 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
350 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF),
351 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF)
352 };
353
354 // Unused at the moment
355 static CONST COLORREF mtext_s3_palette[64] =
356 {
357 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
358 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
359 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
360 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
361 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
362 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
363 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF),
364 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF),
365
366 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
367 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
368 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
369 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
370 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
371 RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA), RGB(0xAA, 0xAA, 0xAA),
372 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF),
373 RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF), RGB(0xFF, 0xFF, 0xFF)
374 };
375
376 // Unused at the moment
377 static CONST COLORREF CgaPalette[16] =
378 {
379 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
380 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
381 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
382 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF)
383 };
384
385 // Unused at the moment
386 static CONST COLORREF CgaPalette2[VGA_MAX_COLORS / 4] =
387 {
388 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
389 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
390 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
391 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
392 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
393 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
394 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
395 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
396 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
397 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
398 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
399 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
400 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
401 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
402 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
403 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF)
404 };
405
406 static CONST COLORREF EgaPalette___16ColorFixed_DOSBox[VGA_MAX_COLORS / 4] =
407 {
408 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
409 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
410
411 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
412 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
413
414
415 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
416 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
417
418 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
419 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
420
421
422
423 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
424 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
425
426 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
427 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
428
429
430 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
431 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
432
433 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
434 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF)
435 };
436
437 // This is the same as TextPalette
438 static CONST COLORREF EgaPalette__HiRes[VGA_MAX_COLORS / 4] =
439 {
440 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
441 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0xAA, 0x00), RGB(0xAA, 0xAA, 0xAA),
442 RGB(0x00, 0x00, 0x55), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xAA, 0x55), RGB(0x00, 0xAA, 0xFF),
443 RGB(0xAA, 0x00, 0x55), RGB(0xAA, 0x00, 0xFF), RGB(0xAA, 0xAA, 0x55), RGB(0xAA, 0xAA, 0xFF),
444
445 RGB(0x00, 0x55, 0x00), RGB(0x00, 0x55, 0xAA), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xAA),
446 RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0x55, 0xAA), RGB(0xAA, 0xFF, 0x00), RGB(0xAA, 0xFF, 0xAA),
447 RGB(0x00, 0x55, 0x55), RGB(0x00, 0x55, 0xFF), RGB(0x00, 0xFF, 0x55), RGB(0x00, 0xFF, 0xFF),
448 RGB(0xAA, 0x55, 0x55), RGB(0xAA, 0x55, 0xFF), RGB(0xAA, 0xFF, 0x55), RGB(0xAA, 0xFF, 0xFF),
449
450
451 RGB(0x55, 0x00, 0x00), RGB(0x55, 0x00, 0xAA), RGB(0x55, 0xAA, 0x00), RGB(0x55, 0xAA, 0xAA),
452 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xAA), RGB(0xFF, 0xAA, 0x00), RGB(0xFF, 0xAA, 0xAA),
453 RGB(0x55, 0x00, 0x55), RGB(0x55, 0x00, 0xFF), RGB(0x55, 0xAA, 0x55), RGB(0x55, 0xAA, 0xFF),
454 RGB(0xFF, 0x00, 0x55), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xAA, 0x55), RGB(0xFF, 0xAA, 0xFF),
455
456 RGB(0x55, 0x55, 0x00), RGB(0x55, 0x55, 0xAA), RGB(0x55, 0xFF, 0x00), RGB(0x55, 0xFF, 0xAA),
457 RGB(0xFF, 0x55, 0x00), RGB(0xFF, 0x55, 0xAA), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xAA),
458 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
459 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF)
460 };
461
462 #define USE_REACTOS_COLORS
463 // #define USE_DOSBOX_COLORS
464
465 /*
466 * Same palette as the default one 'VgaDefaultPalette' in vga.c
467 */
468 #if defined(USE_REACTOS_COLORS)
469
470 // ReactOS colors
471 static CONST COLORREF VgaPalette[VGA_MAX_COLORS] =
472 {
473 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
474 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
475 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
476 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
477 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
478 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
479 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
480 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
481 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
482 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
483 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
484 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
485 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
486 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
487 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
488 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
489 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
490 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
491 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
492 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
493 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
494 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
495 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
496 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
497 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
498 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
499 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
500 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
501 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
502 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
503 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
504 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
505 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
506 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
507 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
508 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
509 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
510 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
511 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
512 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
513 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
514 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
515 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
516 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
517 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
518 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
519 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
520 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
521 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
522 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
523 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
524 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
525 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
526 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
527 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
528 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
529 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
530 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
531 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
532 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
533 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
534 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
535 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
536 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
537 };
538
539 #elif defined(USE_DOSBOX_COLORS)
540
541 // DOSBox colors
542 static CONST COLORREF VgaPalette[VGA_MAX_COLORS] =
543 {
544 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
545 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
546 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
547 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
548 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
549 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
550 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
551 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
552 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
553 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
554 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
555 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
556 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
557 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
558 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
559 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
560
561 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
562 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
563 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
564 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
565 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
566 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
567 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
568 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
569 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
570 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
571 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
572 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
573 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
574 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
575 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
576 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
577
578 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
579 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
580 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
581 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
582 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
583 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
584 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
585 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
586 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
587 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
588 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
589 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
590 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
591 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
592 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
593 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
594
595 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
596 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
597 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
598 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
599 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
600 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
601 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
602 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
603 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
604 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
605 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
606 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
607 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
608 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
609 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
610 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
611 };
612
613 #endif
614
615 /* PRIVATE FUNCTIONS **********************************************************/
616
617 static BOOLEAN BiosKbdBufferPush(WORD Data)
618 {
619 /* Get the location of the element after the tail */
620 WORD NextElement = Bda->KeybdBufferTail + sizeof(WORD);
621
622 /* Wrap it around if it's at or beyond the end */
623 if (NextElement >= Bda->KeybdBufferEnd) NextElement = Bda->KeybdBufferStart;
624
625 /* If it's full, fail */
626 if (NextElement == Bda->KeybdBufferHead) return FALSE;
627
628 /* Put the value in the queue */
629 *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferTail)) = Data;
630 Bda->KeybdBufferTail += sizeof(WORD);
631
632 /* Check if we are at, or have passed, the end of the buffer */
633 if (Bda->KeybdBufferTail >= Bda->KeybdBufferEnd)
634 {
635 /* Return it to the beginning */
636 Bda->KeybdBufferTail = Bda->KeybdBufferStart;
637 }
638
639 /* Return success */
640 return TRUE;
641 }
642
643 static BOOLEAN BiosKbdBufferTop(LPWORD Data)
644 {
645 /* If it's empty, fail */
646 if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE;
647
648 /* Otherwise, get the value and return success */
649 *Data = *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferHead));
650
651 return TRUE;
652 }
653
654 static BOOLEAN BiosKbdBufferPop(VOID)
655 {
656 /* If it's empty, fail */
657 if (Bda->KeybdBufferHead == Bda->KeybdBufferTail) return FALSE;
658
659 /* Remove the value from the queue */
660 Bda->KeybdBufferHead += sizeof(WORD);
661
662 /* Check if we are at, or have passed, the end of the buffer */
663 if (Bda->KeybdBufferHead >= Bda->KeybdBufferEnd)
664 {
665 /* Return it to the beginning */
666 Bda->KeybdBufferHead = Bda->KeybdBufferStart;
667 }
668
669 /* Return success */
670 return TRUE;
671 }
672
673 static VOID BiosReadWindow(LPWORD Buffer, SMALL_RECT Rectangle, BYTE Page)
674 {
675 INT i, j;
676 INT Counter = 0;
677 WORD Character;
678 DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Page * Bda->VideoPageSize);
679
680 for (i = Rectangle.Top; i <= Rectangle.Bottom; i++)
681 {
682 for (j = Rectangle.Left; j <= Rectangle.Right; j++)
683 {
684 /* Read from video memory */
685 VgaReadMemory(VideoAddress + (i * Bda->ScreenColumns + j) * sizeof(WORD),
686 (LPVOID)&Character,
687 sizeof(WORD));
688
689 /* Write the data to the buffer in row order */
690 Buffer[Counter++] = Character;
691 }
692 }
693 }
694
695 static VOID BiosWriteWindow(LPWORD Buffer, SMALL_RECT Rectangle, BYTE Page)
696 {
697 INT i, j;
698 INT Counter = 0;
699 WORD Character;
700 DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Page * Bda->VideoPageSize);
701
702 for (i = Rectangle.Top; i <= Rectangle.Bottom; i++)
703 {
704 for (j = Rectangle.Left; j <= Rectangle.Right; j++)
705 {
706 Character = Buffer[Counter++];
707
708 /* Write to video memory */
709 VgaWriteMemory(VideoAddress + (i * Bda->ScreenColumns + j) * sizeof(WORD),
710 (LPVOID)&Character,
711 sizeof(WORD));
712 }
713 }
714 }
715
716 static BOOLEAN BiosScrollWindow(INT Direction,
717 DWORD Amount,
718 SMALL_RECT Rectangle,
719 BYTE Page,
720 BYTE FillAttribute)
721 {
722 DWORD i;
723 LPWORD WindowData;
724 WORD WindowWidth = Rectangle.Right - Rectangle.Left + 1;
725 WORD WindowHeight = Rectangle.Bottom - Rectangle.Top + 1;
726 DWORD WindowSize = WindowWidth * WindowHeight;
727
728 /* Allocate a buffer for the window */
729 WindowData = (LPWORD)HeapAlloc(GetProcessHeap(),
730 HEAP_ZERO_MEMORY,
731 WindowSize * sizeof(WORD));
732 if (WindowData == NULL) return FALSE;
733
734 /* Read the window data */
735 BiosReadWindow(WindowData, Rectangle, Page);
736
737 if ((Amount == 0)
738 || (((Direction == SCROLL_DIRECTION_UP)
739 || (Direction == SCROLL_DIRECTION_DOWN))
740 && (Amount >= WindowHeight))
741 || (((Direction == SCROLL_DIRECTION_LEFT)
742 || (Direction == SCROLL_DIRECTION_RIGHT))
743 && (Amount >= WindowWidth)))
744 {
745 /* Fill the window */
746 for (i = 0; i < WindowSize; i++)
747 {
748 WindowData[i] = MAKEWORD(' ', FillAttribute);
749 }
750
751 goto Done;
752 }
753
754 switch (Direction)
755 {
756 case SCROLL_DIRECTION_UP:
757 {
758 RtlMoveMemory(WindowData,
759 &WindowData[WindowWidth * Amount],
760 (WindowSize - WindowWidth * Amount) * sizeof(WORD));
761
762 for (i = 0; i < Amount * WindowWidth; i++)
763 {
764 WindowData[WindowSize - i - 1] = MAKEWORD(' ', FillAttribute);
765 }
766
767 break;
768 }
769
770 case SCROLL_DIRECTION_DOWN:
771 {
772 RtlMoveMemory(&WindowData[WindowWidth * Amount],
773 WindowData,
774 (WindowSize - WindowWidth * Amount) * sizeof(WORD));
775
776 for (i = 0; i < Amount * WindowWidth; i++)
777 {
778 WindowData[i] = MAKEWORD(' ', FillAttribute);
779 }
780
781 break;
782 }
783
784 default:
785 {
786 // TODO: NOT IMPLEMENTED!
787 UNIMPLEMENTED;
788 }
789 }
790
791 Done:
792 /* Write back the window data */
793 BiosWriteWindow(WindowData, Rectangle, Page);
794
795 /* Free the window buffer */
796 HeapFree(GetProcessHeap(), 0, WindowData);
797
798 return TRUE;
799 }
800
801 static VOID BiosCopyTextConsoleToVgaMemory(PCOORD ConsoleSize)
802 {
803 PCHAR_INFO CharBuffer;
804 COORD BufferSize = {Bda->ScreenColumns, Bda->ScreenRows + 1};
805 COORD Origin = { 0, 0 };
806 SMALL_RECT ConRect;
807
808 INT i, j;
809 INT Counter = 0;
810 WORD Character;
811 DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
812
813 /* Allocate a temporary buffer for ReadConsoleOutput */
814 CharBuffer = HeapAlloc(GetProcessHeap(),
815 HEAP_ZERO_MEMORY,
816 BufferSize.X * BufferSize.Y
817 * sizeof(CHAR_INFO));
818 if (CharBuffer == NULL) return;
819
820 ConRect.Left = 0;
821 ConRect.Top = ConsoleSize->Y - BufferSize.Y;
822 ConRect.Right = ConRect.Left + BufferSize.X - 1;
823 ConRect.Bottom = ConRect.Top + BufferSize.Y - 1;
824
825 /* Read the data from the console into the temporary buffer... */
826 ReadConsoleOutputA(BiosConsoleOutput,
827 CharBuffer,
828 BufferSize,
829 Origin,
830 &ConRect);
831
832 /* ... and copy the temporary buffer into the VGA memory */
833 for (i = 0; i < BufferSize.Y; i++)
834 {
835 for (j = 0; j < BufferSize.X; j++)
836 {
837 Character = MAKEWORD(CharBuffer[Counter].Char.AsciiChar,
838 (BYTE)CharBuffer[Counter].Attributes);
839 ++Counter;
840
841 /* Write to video memory */
842 VgaWriteMemory(VideoAddress + (i * Bda->ScreenColumns + j) * sizeof(WORD),
843 (LPVOID)&Character,
844 sizeof(WORD));
845 }
846 }
847
848 /* Free the temporary buffer */
849 HeapFree(GetProcessHeap(), 0, CharBuffer);
850 }
851
852 static BOOLEAN VgaSetRegisters(PVGA_REGISTERS Registers)
853 {
854 INT i;
855
856 if (Registers == NULL) return FALSE;
857
858 /* Disable interrupts */
859 setIF(0);
860
861 /*
862 * Set the CRT base address according to the selected mode,
863 * monochrome or color. The following macros:
864 * VGA_INSTAT1_READ, VGA_CRTC_INDEX and VGA_CRTC_DATA are then
865 * used to access the correct VGA I/O ports.
866 */
867 Bda->CrtBasePort = (Registers->Misc & 0x01) ? VGA_CRTC_INDEX_COLOR
868 : VGA_CRTC_INDEX_MONO;
869
870 /* Write the misc register */
871 IOWriteB(VGA_MISC_WRITE, Registers->Misc);
872
873 /* Synchronous reset on */
874 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG);
875 IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_AR);
876
877 /* Write the sequencer registers */
878 for (i = 1; i < VGA_SEQ_MAX_REG; i++)
879 {
880 IOWriteB(VGA_SEQ_INDEX, i);
881 IOWriteB(VGA_SEQ_DATA, Registers->Sequencer[i]);
882 }
883
884 /* Synchronous reset off */
885 IOWriteB(VGA_SEQ_INDEX, VGA_SEQ_RESET_REG);
886 IOWriteB(VGA_SEQ_DATA , VGA_SEQ_RESET_SR | VGA_SEQ_RESET_AR);
887
888 /* Unlock CRTC registers 0-7 */
889 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_END_HORZ_BLANKING_REG);
890 IOWriteB(VGA_CRTC_DATA, IOReadB(VGA_CRTC_DATA) | 0x80);
891 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_VERT_RETRACE_END_REG);
892 IOWriteB(VGA_CRTC_DATA, IOReadB(VGA_CRTC_DATA) & ~0x80);
893 // Make sure they remain unlocked
894 Registers->CRT[VGA_CRTC_END_HORZ_BLANKING_REG] |= 0x80;
895 Registers->CRT[VGA_CRTC_VERT_RETRACE_END_REG] &= ~0x80;
896
897 /* Write the CRTC registers */
898 for (i = 0; i < VGA_CRTC_MAX_REG; i++)
899 {
900 IOWriteB(VGA_CRTC_INDEX, i);
901 IOWriteB(VGA_CRTC_DATA, Registers->CRT[i]);
902 }
903
904 /* Write the GC registers */
905 for (i = 0; i < VGA_GC_MAX_REG; i++)
906 {
907 IOWriteB(VGA_GC_INDEX, i);
908 IOWriteB(VGA_GC_DATA, Registers->Graphics[i]);
909 }
910
911 /* Write the AC registers */
912 // DbgPrint("\n");
913 for (i = 0; i < VGA_AC_MAX_REG; i++)
914 {
915 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
916 IOWriteB(VGA_AC_INDEX, i);
917 IOWriteB(VGA_AC_WRITE, Registers->Attribute[i]);
918 // DbgPrint("Registers->Attribute[%d] = %d\n", i, Registers->Attribute[i]);
919 }
920 // DbgPrint("\n");
921
922 /* Set the PEL mask */
923 IOWriteB(VGA_DAC_MASK, 0xFF);
924
925 /* Enable screen and disable palette access */
926 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
927 IOWriteB(VGA_AC_INDEX, 0x20);
928
929 /* Enable interrupts */
930 setIF(1);
931
932 return TRUE;
933 }
934
935 static VOID VgaSetPalette(const COLORREF* Palette, ULONG Size)
936 {
937 ULONG i;
938
939 // /* Disable screen and enable palette access */
940 // IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
941 // IOWriteB(VGA_AC_INDEX, 0x00);
942
943 for (i = 0; i < Size; i++)
944 {
945 IOWriteB(VGA_DAC_WRITE_INDEX, i);
946 IOWriteB(VGA_DAC_DATA, VGA_COLOR_TO_DAC(GetRValue(Palette[i])));
947 IOWriteB(VGA_DAC_DATA, VGA_COLOR_TO_DAC(GetGValue(Palette[i])));
948 IOWriteB(VGA_DAC_DATA, VGA_COLOR_TO_DAC(GetBValue(Palette[i])));
949 }
950
951 /* The following step might be optional */
952 for (i = Size; i < VGA_MAX_COLORS; i++)
953 {
954 IOWriteB(VGA_DAC_WRITE_INDEX, i);
955 IOWriteB(VGA_DAC_DATA, VGA_COLOR_TO_DAC(0x00));
956 IOWriteB(VGA_DAC_DATA, VGA_COLOR_TO_DAC(0x00));
957 IOWriteB(VGA_DAC_DATA, VGA_COLOR_TO_DAC(0x00));
958 }
959
960 /* Enable screen and disable palette access */
961 // IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
962 // IOWriteB(VGA_AC_INDEX, 0x20);
963 }
964
965 static VOID VgaChangePalette(BYTE ModeNumber)
966 {
967 const COLORREF* Palette;
968 ULONG Size;
969
970 if (ModeNumber >= 0x13)
971 {
972 /* VGA modes */
973 Palette = VgaPalette;
974 Size = sizeof(VgaPalette)/sizeof(VgaPalette[0]);
975 }
976 else if (ModeNumber == 0x10)
977 {
978 /* EGA HiRes mode */
979 Palette = EgaPalette__HiRes;
980 Size = sizeof(EgaPalette__HiRes)/sizeof(EgaPalette__HiRes[0]);
981 }
982 else // if ((ModeNumber == 0x0D) || (ModeNumber == 0x0E))
983 {
984 /* EGA modes */
985 Palette = EgaPalette___16ColorFixed_DOSBox;
986 Size = sizeof(EgaPalette___16ColorFixed_DOSBox)/sizeof(EgaPalette___16ColorFixed_DOSBox[0]);
987 }
988
989 VgaSetPalette(Palette, Size);
990 }
991
992 static VOID BiosGetCursorPosition(PBYTE Row, PBYTE Column, BYTE Page)
993 {
994 /* Make sure the selected video page is valid */
995 if (Page >= BIOS_MAX_PAGES) return;
996
997 /* Get the cursor location */
998 *Row = HIBYTE(Bda->CursorPosition[Page]);
999 *Column = LOBYTE(Bda->CursorPosition[Page]);
1000 }
1001
1002 static VOID BiosSetCursorPosition(BYTE Row, BYTE Column, BYTE Page)
1003 {
1004 /* Make sure the selected video page is valid */
1005 if (Page >= BIOS_MAX_PAGES) return;
1006
1007 /* Update the position in the BDA */
1008 Bda->CursorPosition[Page] = MAKEWORD(Column, Row);
1009
1010 /* Check if this is the current video page */
1011 if (Page == Bda->VideoPage)
1012 {
1013 WORD Offset = Row * Bda->ScreenColumns + Column;
1014
1015 /* Modify the CRTC registers */
1016 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_LOW_REG);
1017 IOWriteB(VGA_CRTC_DATA , LOBYTE(Offset));
1018 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_LOC_HIGH_REG);
1019 IOWriteB(VGA_CRTC_DATA , HIBYTE(Offset));
1020 }
1021 }
1022
1023 BYTE BiosGetVideoMode(VOID)
1024 {
1025 return Bda->VideoMode;
1026 }
1027
1028 static BOOLEAN BiosSetVideoMode(BYTE ModeNumber)
1029 {
1030 BYTE Page;
1031
1032 COORD Resolution;
1033 PVGA_REGISTERS VgaMode = VideoModes[ModeNumber];
1034
1035 DPRINT1("Switching to mode %Xh; VgaMode = 0x%p\n", ModeNumber, VgaMode);
1036
1037 if (!VgaSetRegisters(VgaMode)) return FALSE;
1038
1039 VgaChangePalette(ModeNumber);
1040
1041 /*
1042 * IBM standard modes do not clear the screen if the
1043 * high bit of AL is set (EGA or higher only).
1044 * See Ralf Brown: http://www.ctyme.com/intr/rb-0069.htm
1045 * for more information.
1046 */
1047 if ((ModeNumber & 0x08) == 0) VgaClearMemory();
1048
1049 // Bda->CrtModeControl;
1050 // Bda->CrtColorPaletteMask;
1051 // Bda->EGAFlags;
1052 // Bda->VGAFlags;
1053
1054 /* Update the values in the BDA */
1055 Bda->VideoMode = ModeNumber;
1056 Bda->VideoPageSize = VideoModePageSize[ModeNumber];
1057 Bda->VideoPage = 0;
1058 Bda->VideoPageOffset = Bda->VideoPage * Bda->VideoPageSize;
1059
1060 /* Set the start address in the CRTC */
1061 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_START_ADDR_LOW_REG);
1062 IOWriteB(VGA_CRTC_DATA , LOBYTE(Bda->VideoPageOffset));
1063 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_START_ADDR_HIGH_REG);
1064 IOWriteB(VGA_CRTC_DATA , HIBYTE(Bda->VideoPageOffset));
1065
1066 /* Get the character height */
1067 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_MAX_SCAN_LINE_REG);
1068 Bda->CharacterHeight = 1 + (IOReadB(VGA_CRTC_DATA) & 0x1F);
1069
1070 Resolution = VgaGetDisplayResolution();
1071 Bda->ScreenColumns = Resolution.X;
1072 Bda->ScreenRows = Resolution.Y - 1;
1073
1074 /* Set the cursor position for each page */
1075 for (Page = 0; Page < BIOS_MAX_PAGES; ++Page)
1076 BiosSetCursorPosition(0, 0, Page);
1077
1078 return TRUE;
1079 }
1080
1081 static BOOLEAN BiosSetVideoPage(BYTE PageNumber)
1082 {
1083 BYTE Row, Column;
1084
1085 /* Check if the page exists */
1086 if (PageNumber >= BIOS_MAX_PAGES) return FALSE;
1087
1088 /* Check if this is the same page */
1089 if (PageNumber == Bda->VideoPage) return TRUE;
1090
1091 /* Update the values in the BDA */
1092 Bda->VideoPage = PageNumber;
1093 Bda->VideoPageOffset = Bda->VideoPage * Bda->VideoPageSize;
1094
1095 /* Set the start address in the CRTC */
1096 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_START_ADDR_LOW_REG);
1097 IOWriteB(VGA_CRTC_DATA , LOBYTE(Bda->VideoPageOffset));
1098 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_START_ADDR_HIGH_REG);
1099 IOWriteB(VGA_CRTC_DATA , HIBYTE(Bda->VideoPageOffset));
1100
1101 /*
1102 * Get the cursor location (we don't update anything on the BIOS side
1103 * but we update the cursor location on the VGA side).
1104 */
1105 BiosGetCursorPosition(&Row, &Column, PageNumber);
1106 BiosSetCursorPosition(Row, Column, PageNumber);
1107
1108 return TRUE;
1109 }
1110
1111 static VOID WINAPI BiosVideoService(LPWORD Stack)
1112 {
1113 switch (getAH())
1114 {
1115 /* Set Video Mode */
1116 case 0x00:
1117 {
1118 BiosSetVideoMode(getAL());
1119 break;
1120 }
1121
1122 /* Set Text-Mode Cursor Shape */
1123 case 0x01:
1124 {
1125 /* Update the BDA */
1126 Bda->CursorStartLine = getCH();
1127 Bda->CursorEndLine = getCL();
1128
1129 /* Modify the CRTC registers */
1130 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_START_REG);
1131 IOWriteB(VGA_CRTC_DATA , Bda->CursorStartLine);
1132 IOWriteB(VGA_CRTC_INDEX, VGA_CRTC_CURSOR_END_REG);
1133 IOWriteB(VGA_CRTC_DATA , Bda->CursorEndLine);
1134
1135 break;
1136 }
1137
1138 /* Set Cursor Position */
1139 case 0x02:
1140 {
1141 BiosSetCursorPosition(getDH(), getDL(), getBH());
1142 break;
1143 }
1144
1145 /* Get Cursor Position */
1146 case 0x03:
1147 {
1148 /* Make sure the selected video page exists */
1149 if (getBH() >= BIOS_MAX_PAGES) break;
1150
1151 /* Return the result */
1152 setAX(0);
1153 setCX(MAKEWORD(Bda->CursorEndLine, Bda->CursorStartLine));
1154 setDX(Bda->CursorPosition[getBH()]);
1155 break;
1156 }
1157
1158 /* Query Light Pen */
1159 case 0x04:
1160 {
1161 /*
1162 * On modern BIOSes, this function returns 0
1163 * so that we can ignore the other registers.
1164 */
1165 setAX(0);
1166 break;
1167 }
1168
1169 /* Select Active Display Page */
1170 case 0x05:
1171 {
1172 BiosSetVideoPage(getAL());
1173 break;
1174 }
1175
1176 /* Scroll Window Up/Down */
1177 case 0x06:
1178 case 0x07:
1179 {
1180 SMALL_RECT Rectangle = { getCL(), getCH(), getDL(), getDH() };
1181
1182 /* Call the internal function */
1183 BiosScrollWindow((getAH() == 0x06) ? SCROLL_DIRECTION_UP
1184 : SCROLL_DIRECTION_DOWN,
1185 getAL(),
1186 Rectangle,
1187 Bda->VideoPage,
1188 getBH());
1189
1190 break;
1191 }
1192
1193 /* Read/Write Character From Cursor Position */
1194 case 0x08:
1195 case 0x09:
1196 case 0x0A:
1197 {
1198 WORD CharacterData = MAKEWORD(getAL(), getBL());
1199 BYTE Page = getBH();
1200 DWORD Offset;
1201
1202 /* Check if the page exists */
1203 if (Page >= BIOS_MAX_PAGES) break;
1204
1205 /* Find the offset of the character */
1206 Offset = Page * Bda->VideoPageSize +
1207 (HIBYTE(Bda->CursorPosition[Page]) * Bda->ScreenColumns +
1208 LOBYTE(Bda->CursorPosition[Page])) * 2;
1209
1210 if (getAH() == 0x08)
1211 {
1212 /* Read from the video memory */
1213 VgaReadMemory(TO_LINEAR(TEXT_VIDEO_SEG, Offset),
1214 (LPVOID)&CharacterData,
1215 sizeof(WORD));
1216
1217 /* Return the character in AX */
1218 setAX(CharacterData);
1219 }
1220 else
1221 {
1222 /* Write to video memory */
1223 VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG, Offset),
1224 (LPVOID)&CharacterData,
1225 (getBH() == 0x09) ? sizeof(WORD) : sizeof(BYTE));
1226 }
1227
1228 break;
1229 }
1230
1231 /* Teletype Output */
1232 case 0x0E:
1233 {
1234 BiosPrintCharacter(getAL(), getBL(), getBH());
1235 break;
1236 }
1237
1238 /* Get Current Video Mode */
1239 case 0x0F:
1240 {
1241 setAX(MAKEWORD(Bda->VideoMode, Bda->ScreenColumns));
1242 setBX(MAKEWORD(getBL(), Bda->VideoPage));
1243 break;
1244 }
1245
1246 /* Palette Control */
1247 case 0x10:
1248 {
1249 switch (getAL())
1250 {
1251 /* Set Single Palette Register */
1252 case 0x00:
1253 {
1254 /* Write the index */
1255 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1256 IOWriteB(VGA_AC_INDEX, getBL());
1257
1258 /* Write the data */
1259 IOWriteB(VGA_AC_WRITE, getBH());
1260
1261 /* Enable screen and disable palette access */
1262 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1263 IOWriteB(VGA_AC_INDEX, 0x20);
1264 break;
1265 }
1266
1267 /* Set Overscan Color */
1268 case 0x01:
1269 {
1270 /* Write the index */
1271 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1272 IOWriteB(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
1273
1274 /* Write the data */
1275 IOWriteB(VGA_AC_WRITE, getBH());
1276
1277 /* Enable screen and disable palette access */
1278 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1279 IOWriteB(VGA_AC_INDEX, 0x20);
1280 break;
1281 }
1282
1283 /* Set All Palette Registers */
1284 case 0x02:
1285 {
1286 INT i;
1287 LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
1288
1289 /* Set the palette registers */
1290 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1291 {
1292 /* Write the index */
1293 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1294 IOWriteB(VGA_AC_INDEX, i);
1295
1296 /* Write the data */
1297 IOWriteB(VGA_AC_WRITE, Buffer[i]);
1298 }
1299
1300 /* Set the overscan register */
1301 IOWriteB(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
1302 IOWriteB(VGA_AC_WRITE, Buffer[VGA_AC_PAL_F_REG + 1]);
1303
1304 /* Enable screen and disable palette access */
1305 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1306 IOWriteB(VGA_AC_INDEX, 0x20);
1307 break;
1308 }
1309
1310 /* Get Single Palette Register */
1311 case 0x07:
1312 {
1313 /* Write the index */
1314 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1315 IOWriteB(VGA_AC_INDEX, getBL());
1316
1317 /* Read the data */
1318 setBH(IOReadB(VGA_AC_READ));
1319
1320 /* Enable screen and disable palette access */
1321 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1322 IOWriteB(VGA_AC_INDEX, 0x20);
1323 break;
1324 }
1325
1326 /* Get Overscan Color */
1327 case 0x08:
1328 {
1329 /* Write the index */
1330 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1331 IOWriteB(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
1332
1333 /* Read the data */
1334 setBH(IOReadB(VGA_AC_READ));
1335
1336 /* Enable screen and disable palette access */
1337 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1338 IOWriteB(VGA_AC_INDEX, 0x20);
1339 break;
1340 }
1341
1342 /* Get All Palette Registers */
1343 case 0x09:
1344 {
1345 INT i;
1346 LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
1347
1348 /* Get the palette registers */
1349 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1350 {
1351 /* Write the index */
1352 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1353 IOWriteB(VGA_AC_INDEX, i);
1354
1355 /* Read the data */
1356 Buffer[i] = IOReadB(VGA_AC_READ);
1357 }
1358
1359 /* Get the overscan register */
1360 IOWriteB(VGA_AC_INDEX, VGA_AC_OVERSCAN_REG);
1361 Buffer[VGA_AC_PAL_F_REG + 1] = IOReadB(VGA_AC_READ);
1362
1363 /* Enable screen and disable palette access */
1364 IOReadB(VGA_INSTAT1_READ); // Put the AC register into index state
1365 IOWriteB(VGA_AC_INDEX, 0x20);
1366 break;
1367 }
1368
1369 /* Set Individual DAC Register */
1370 case 0x10:
1371 {
1372 /* Write the index */
1373 // Certainly in BL and not in BX as said by Ralf Brown...
1374 IOWriteB(VGA_DAC_WRITE_INDEX, getBL());
1375
1376 /* Write the data in this order: Red, Green, Blue */
1377 IOWriteB(VGA_DAC_DATA, getDH());
1378 IOWriteB(VGA_DAC_DATA, getCH());
1379 IOWriteB(VGA_DAC_DATA, getCL());
1380
1381 break;
1382 }
1383
1384 /* Set Block of DAC Registers */
1385 case 0x12:
1386 {
1387 INT i;
1388 LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
1389
1390 /* Write the index */
1391 // Certainly in BL and not in BX as said by Ralf Brown...
1392 IOWriteB(VGA_DAC_WRITE_INDEX, getBL());
1393
1394 for (i = 0; i < getCX(); i++)
1395 {
1396 /* Write the data in this order: Red, Green, Blue */
1397 IOWriteB(VGA_DAC_DATA, *Buffer++);
1398 IOWriteB(VGA_DAC_DATA, *Buffer++);
1399 IOWriteB(VGA_DAC_DATA, *Buffer++);
1400 }
1401
1402 break;
1403 }
1404
1405 /* Get Individual DAC Register */
1406 case 0x15:
1407 {
1408 /* Write the index */
1409 IOWriteB(VGA_DAC_READ_INDEX, getBL());
1410
1411 /* Read the data in this order: Red, Green, Blue */
1412 setDH(IOReadB(VGA_DAC_DATA));
1413 setCH(IOReadB(VGA_DAC_DATA));
1414 setCL(IOReadB(VGA_DAC_DATA));
1415
1416 break;
1417 }
1418
1419 /* Get Block of DAC Registers */
1420 case 0x17:
1421 {
1422 INT i;
1423 LPBYTE Buffer = SEG_OFF_TO_PTR(getES(), getDX());
1424
1425 /* Write the index */
1426 // Certainly in BL and not in BX as said by Ralf Brown...
1427 IOWriteB(VGA_DAC_READ_INDEX, getBL());
1428
1429 for (i = 0; i < getCX(); i++)
1430 {
1431 /* Write the data in this order: Red, Green, Blue */
1432 *Buffer++ = IOReadB(VGA_DAC_DATA);
1433 *Buffer++ = IOReadB(VGA_DAC_DATA);
1434 *Buffer++ = IOReadB(VGA_DAC_DATA);
1435 }
1436
1437 break;
1438 }
1439
1440 default:
1441 {
1442 DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n",
1443 getAL());
1444 break;
1445 }
1446 }
1447
1448 break;
1449 }
1450
1451 /* Scroll Window */
1452 case 0x12:
1453 {
1454 SMALL_RECT Rectangle = { getCL(), getCH(), getDL(), getDH() };
1455
1456 /* Call the internal function */
1457 BiosScrollWindow(getBL(),
1458 getAL(),
1459 Rectangle,
1460 Bda->VideoPage,
1461 DEFAULT_ATTRIBUTE);
1462
1463 break;
1464 }
1465
1466 /* Display combination code */
1467 case 0x1A:
1468 {
1469 switch(getAL())
1470 {
1471 case 0x00: /* Get Display combiantion code */
1472 setAX(MAKEWORD(0x1A, 0x1A));
1473 setBX(MAKEWORD(0x08, 0x00)); /* VGA w/ color analog display */
1474 break;
1475 case 0x01: /* Set Display combination code */
1476 DPRINT1("Set Display combination code - Unsupported\n");
1477 break;
1478 default:
1479 break;
1480 }
1481 break;
1482 }
1483
1484 default:
1485 {
1486 DPRINT1("BIOS Function INT 10h, AH = 0x%02X NOT IMPLEMENTED\n",
1487 getAH());
1488 }
1489 }
1490 }
1491
1492 static VOID WINAPI BiosEquipmentService(LPWORD Stack)
1493 {
1494 /* Return the equipment list */
1495 setAX(Bda->EquipmentList);
1496 }
1497
1498 static VOID WINAPI BiosGetMemorySize(LPWORD Stack)
1499 {
1500 /* Return the conventional memory size in kB, typically 640 kB */
1501 setAX(Bda->MemorySize);
1502 }
1503
1504 static VOID WINAPI BiosMiscService(LPWORD Stack)
1505 {
1506 switch (getAH())
1507 {
1508 /* Copy Extended Memory */
1509 case 0x87:
1510 {
1511 DWORD Count = (DWORD)getCX() * 2;
1512 PFAST486_GDT_ENTRY Gdt = (PFAST486_GDT_ENTRY)SEG_OFF_TO_PTR(getES(), getSI());
1513 DWORD SourceBase = Gdt[2].Base + (Gdt[2].BaseMid << 16) + (Gdt[2].BaseHigh << 24);
1514 DWORD SourceLimit = Gdt[2].Limit + (Gdt[2].LimitHigh << 16);
1515 DWORD DestBase = Gdt[3].Base + (Gdt[3].BaseMid << 16) + (Gdt[3].BaseHigh << 24);
1516 DWORD DestLimit = Gdt[3].Limit + (Gdt[3].LimitHigh << 16);
1517
1518 /* Check for flags */
1519 if (Gdt[2].Granularity) SourceLimit = (SourceLimit << 12) | 0xFFF;
1520 if (Gdt[3].Granularity) DestLimit = (DestLimit << 12) | 0xFFF;
1521
1522 if ((Count > SourceLimit) || (Count > DestLimit))
1523 {
1524 setAX(0x80);
1525 Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF;
1526
1527 break;
1528 }
1529
1530 /* Copy */
1531 RtlMoveMemory((PVOID)((ULONG_PTR)BaseAddress + DestBase),
1532 (PVOID)((ULONG_PTR)BaseAddress + SourceBase),
1533 Count);
1534
1535 setAX(ERROR_SUCCESS);
1536 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1537 break;
1538 }
1539
1540 /* Get Extended Memory Size */
1541 case 0x88:
1542 {
1543 /* Return the number of KB of RAM after 1 MB */
1544 setAX((MAX_ADDRESS - 0x100000) / 1024);
1545
1546 /* Clear CF */
1547 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF;
1548
1549 break;
1550 }
1551
1552 default:
1553 {
1554 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
1555 getAH());
1556 }
1557 }
1558 }
1559
1560 static VOID WINAPI BiosKeyboardService(LPWORD Stack)
1561 {
1562 switch (getAH())
1563 {
1564 /* Wait for keystroke and read */
1565 case 0x00:
1566 /* Wait for extended keystroke and read */
1567 case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
1568 {
1569 /* Read the character (and wait if necessary) */
1570 setAX(BiosGetCharacter());
1571 break;
1572 }
1573
1574 /* Get keystroke status */
1575 case 0x01:
1576 /* Get extended keystroke status */
1577 case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
1578 {
1579 WORD Data = BiosPeekCharacter();
1580
1581 if (Data != 0xFFFF)
1582 {
1583 /* There is a character, clear ZF and return it */
1584 Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_ZF;
1585 setAX(Data);
1586 }
1587 else
1588 {
1589 /* No character, set ZF */
1590 Stack[STACK_FLAGS] |= EMULATOR_FLAG_ZF;
1591 }
1592
1593 break;
1594 }
1595
1596 /* Get shift status */
1597 case 0x02:
1598 {
1599 /* Return the lower byte of the keyboard shift status word */
1600 setAL(LOBYTE(Bda->KeybdShiftFlags));
1601 break;
1602 }
1603
1604 /* Reserved */
1605 case 0x04:
1606 {
1607 DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
1608 break;
1609 }
1610
1611 /* Push keystroke */
1612 case 0x05:
1613 {
1614 /* Return 0 if success, 1 if failure */
1615 setAL(BiosKbdBufferPush(getCX()) == FALSE);
1616 break;
1617 }
1618
1619 /* Get extended shift status */
1620 case 0x12:
1621 {
1622 /*
1623 * Be careful! The returned word is similar to Bda->KeybdShiftFlags
1624 * but the high byte is organized differently:
1625 * the bytes 2 and 3 of the high byte are not the same...
1626 */
1627 WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF);
1628
1629 /* Return the extended keyboard shift status word */
1630 setAX(KeybdShiftFlags);
1631 break;
1632 }
1633
1634 default:
1635 {
1636 DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
1637 getAH());
1638 }
1639 }
1640 }
1641
1642 static VOID WINAPI BiosTimeService(LPWORD Stack)
1643 {
1644 switch (getAH())
1645 {
1646 case 0x00:
1647 {
1648 /* Set AL to 1 if midnight had passed, 0 otherwise */
1649 setAL(Bda->MidnightPassed ? 0x01 : 0x00);
1650
1651 /* Return the tick count in CX:DX */
1652 setCX(HIWORD(Bda->TickCounter));
1653 setDX(LOWORD(Bda->TickCounter));
1654
1655 /* Reset the midnight flag */
1656 Bda->MidnightPassed = FALSE;
1657
1658 break;
1659 }
1660
1661 case 0x01:
1662 {
1663 /* Set the tick count to CX:DX */
1664 Bda->TickCounter = MAKELONG(getDX(), getCX());
1665
1666 /* Reset the midnight flag */
1667 Bda->MidnightPassed = FALSE;
1668
1669 break;
1670 }
1671
1672 default:
1673 {
1674 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
1675 getAH());
1676 }
1677 }
1678 }
1679
1680 static VOID WINAPI BiosSystemTimerInterrupt(LPWORD Stack)
1681 {
1682 /* Increase the system tick count */
1683 Bda->TickCounter++;
1684 }
1685
1686 /* PUBLIC FUNCTIONS ***********************************************************/
1687
1688 WORD BiosPeekCharacter(VOID)
1689 {
1690 WORD CharacterData = 0;
1691
1692 /* Get the key from the queue, but don't remove it */
1693 if (BiosKbdBufferTop(&CharacterData)) return CharacterData;
1694 else return 0xFFFF;
1695 }
1696
1697 WORD BiosGetCharacter(VOID)
1698 {
1699 WORD CharacterData = 0;
1700
1701 /* Check if there is a key available */
1702 if (BiosKbdBufferTop(&CharacterData))
1703 {
1704 /* A key was available, remove it from the queue */
1705 BiosKbdBufferPop();
1706 }
1707 else
1708 {
1709 /* No key available. Set the handler CF to repeat the BOP */
1710 setCF(1);
1711 // CharacterData = 0xFFFF;
1712 }
1713
1714 return CharacterData;
1715 }
1716
1717 VOID BiosPrintCharacter(CHAR Character, BYTE Attribute, BYTE Page)
1718 {
1719 WORD CharData = MAKEWORD(Character, Attribute);
1720 BYTE Row, Column;
1721
1722 /* Make sure the page exists */
1723 if (Page >= BIOS_MAX_PAGES) return;
1724
1725 /* Get the cursor location */
1726 BiosGetCursorPosition(&Row, &Column, Page);
1727
1728 if (Character == '\a')
1729 {
1730 /* Bell control character */
1731 // NOTE: We may use what the terminal emulator offers to us...
1732 Beep(800, 200);
1733 return;
1734 }
1735 else if (Character == '\b')
1736 {
1737 /* Backspace control character */
1738 if (Column > 0)
1739 {
1740 Column--;
1741 }
1742 else if (Row > 0)
1743 {
1744 Column = Bda->ScreenColumns - 1;
1745 Row--;
1746 }
1747
1748 /* Erase the existing character */
1749 CharData = MAKEWORD(' ', Attribute);
1750 EmulatorWriteMemory(&EmulatorContext,
1751 TO_LINEAR(TEXT_VIDEO_SEG,
1752 Page * Bda->VideoPageSize +
1753 (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
1754 (LPVOID)&CharData,
1755 sizeof(WORD));
1756 }
1757 else if (Character == '\t')
1758 {
1759 /* Horizontal Tabulation control character */
1760 do
1761 {
1762 // Taken from DOSBox
1763 BiosPrintCharacter(' ', Attribute, Page);
1764 BiosGetCursorPosition(&Row, &Column, Page);
1765 } while (Column % 8);
1766 }
1767 else if (Character == '\n')
1768 {
1769 /* Line Feed control character */
1770 Row++;
1771 }
1772 else if (Character == '\r')
1773 {
1774 /* Carriage Return control character */
1775 Column = 0;
1776 }
1777 else
1778 {
1779 /* Default character */
1780
1781 /* Write the character */
1782 EmulatorWriteMemory(&EmulatorContext,
1783 TO_LINEAR(TEXT_VIDEO_SEG,
1784 Page * Bda->VideoPageSize +
1785 (Row * Bda->ScreenColumns + Column) * sizeof(WORD)),
1786 (LPVOID)&CharData,
1787 sizeof(WORD));
1788
1789 /* Advance the cursor */
1790 Column++;
1791 }
1792
1793 /* Check if it passed the end of the row */
1794 if (Column >= Bda->ScreenColumns)
1795 {
1796 /* Return to the first column and go to the next line */
1797 Column = 0;
1798 Row++;
1799 }
1800
1801 /* Scroll the screen up if needed */
1802 if (Row > Bda->ScreenRows)
1803 {
1804 /* The screen must be scrolled up */
1805 SMALL_RECT Rectangle = { 0, 0, Bda->ScreenColumns - 1, Bda->ScreenRows };
1806
1807 BiosScrollWindow(SCROLL_DIRECTION_UP,
1808 1,
1809 Rectangle,
1810 Page,
1811 DEFAULT_ATTRIBUTE);
1812
1813 Row--;
1814 }
1815
1816 /* Set the cursor position */
1817 BiosSetCursorPosition(Row, Column, Page);
1818 }
1819
1820 BOOLEAN BiosInitialize(VOID)
1821 {
1822 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
1823
1824 /* Initialize the BDA */
1825 Bda = (PBIOS_DATA_AREA)SEG_OFF_TO_PTR(BDA_SEGMENT, 0);
1826 Bda->EquipmentList = BIOS_EQUIPMENT_LIST;
1827 /*
1828 * Conventional memory size is 640 kB,
1829 * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
1830 * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
1831 * for more information.
1832 */
1833 Bda->MemorySize = 0x0280;
1834 Bda->KeybdBufferStart = FIELD_OFFSET(BIOS_DATA_AREA, KeybdBuffer);
1835 Bda->KeybdBufferEnd = Bda->KeybdBufferStart + BIOS_KBD_BUFFER_SIZE * sizeof(WORD);
1836 Bda->KeybdBufferHead = Bda->KeybdBufferTail = 0;
1837
1838 /* Initialize the 32-bit Interrupt system */
1839 InitializeInt32(BIOS_SEGMENT);
1840
1841 /* Register the BIOS 32-bit Interrupts */
1842 RegisterInt32(BIOS_VIDEO_INTERRUPT , BiosVideoService );
1843 RegisterInt32(BIOS_EQUIPMENT_INTERRUPT, BiosEquipmentService );
1844 RegisterInt32(BIOS_MEMORY_SIZE , BiosGetMemorySize );
1845 RegisterInt32(BIOS_MISC_INTERRUPT , BiosMiscService );
1846 RegisterInt32(BIOS_KBD_INTERRUPT , BiosKeyboardService );
1847 RegisterInt32(BIOS_TIME_INTERRUPT , BiosTimeService );
1848 RegisterInt32(BIOS_SYS_TIMER_INTERRUPT, BiosSystemTimerInterrupt);
1849
1850 /* Some interrupts are in fact addresses to tables */
1851 ((PDWORD)BaseAddress)[0x1D] = (DWORD)NULL;
1852 ((PDWORD)BaseAddress)[0x1E] = (DWORD)NULL;
1853 ((PDWORD)BaseAddress)[0x1F] = (DWORD)NULL;
1854
1855 ((PDWORD)BaseAddress)[0x41] = (DWORD)NULL;
1856 ((PDWORD)BaseAddress)[0x43] = (DWORD)NULL;
1857 ((PDWORD)BaseAddress)[0x44] = (DWORD)NULL;
1858 ((PDWORD)BaseAddress)[0x46] = (DWORD)NULL;
1859 ((PDWORD)BaseAddress)[0x48] = (DWORD)NULL;
1860 ((PDWORD)BaseAddress)[0x49] = (DWORD)NULL;
1861
1862 /* Get the input handle to the real console, and check for success */
1863 BiosConsoleInput = CreateFileW(L"CONIN$",
1864 GENERIC_READ | GENERIC_WRITE,
1865 FILE_SHARE_READ | FILE_SHARE_WRITE,
1866 NULL,
1867 OPEN_EXISTING,
1868 0,
1869 NULL);
1870 if (BiosConsoleInput == INVALID_HANDLE_VALUE)
1871 {
1872 return FALSE;
1873 }
1874
1875 /* Get the output handle to the real console, and check for success */
1876 BiosConsoleOutput = CreateFileW(L"CONOUT$",
1877 GENERIC_READ | GENERIC_WRITE,
1878 FILE_SHARE_READ | FILE_SHARE_WRITE,
1879 NULL,
1880 OPEN_EXISTING,
1881 0,
1882 NULL);
1883 if (BiosConsoleOutput == INVALID_HANDLE_VALUE)
1884 {
1885 CloseHandle(BiosConsoleInput);
1886 return FALSE;
1887 }
1888
1889 /* Save the original input and output console modes */
1890 if (!GetConsoleMode(BiosConsoleInput , &BiosSavedConInMode ) ||
1891 !GetConsoleMode(BiosConsoleOutput, &BiosSavedConOutMode))
1892 {
1893 CloseHandle(BiosConsoleOutput);
1894 CloseHandle(BiosConsoleInput);
1895 return FALSE;
1896 }
1897
1898 /* Save the original cursor and console screen buffer information */
1899 if (!GetConsoleCursorInfo(BiosConsoleOutput, &BiosSavedCursorInfo) ||
1900 !GetConsoleScreenBufferInfo(BiosConsoleOutput, &BiosSavedBufferInfo))
1901 {
1902 CloseHandle(BiosConsoleOutput);
1903 CloseHandle(BiosConsoleInput);
1904 return FALSE;
1905 }
1906
1907 /* Initialize VGA */
1908 if (!VgaInitialize(BiosConsoleOutput))
1909 {
1910 CloseHandle(BiosConsoleOutput);
1911 CloseHandle(BiosConsoleInput);
1912 return FALSE;
1913 }
1914
1915 /* Set the default video mode */
1916 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
1917
1918 GetConsoleScreenBufferInfo(BiosConsoleOutput, &ConsoleInfo);
1919
1920 /* Copy console data into VGA memory */
1921 BiosCopyTextConsoleToVgaMemory(&ConsoleInfo.dwSize);
1922
1923 /* Update the cursor position for the current page */
1924 BiosSetCursorPosition(ConsoleInfo.dwCursorPosition.Y,
1925 ConsoleInfo.dwCursorPosition.X,
1926 Bda->VideoPage);
1927
1928 /* Set the console input mode */
1929 SetConsoleMode(BiosConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
1930
1931 /* Initialize PS2 */
1932 PS2Initialize(BiosConsoleInput);
1933
1934 /* Initialize the PIC */
1935 IOWriteB(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
1936 IOWriteB(PIC_SLAVE_CMD , PIC_ICW1 | PIC_ICW1_ICW4);
1937
1938 /* Set the interrupt offsets */
1939 IOWriteB(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
1940 IOWriteB(PIC_SLAVE_DATA , BIOS_PIC_SLAVE_INT);
1941
1942 /* Tell the master PIC there is a slave at IRQ 2 */
1943 IOWriteB(PIC_MASTER_DATA, 1 << 2);
1944 IOWriteB(PIC_SLAVE_DATA , 2);
1945
1946 /* Make sure the PIC is in 8086 mode */
1947 IOWriteB(PIC_MASTER_DATA, PIC_ICW4_8086);
1948 IOWriteB(PIC_SLAVE_DATA , PIC_ICW4_8086);
1949
1950 /* Clear the masks for both PICs */
1951 IOWriteB(PIC_MASTER_DATA, 0x00);
1952 IOWriteB(PIC_SLAVE_DATA , 0x00);
1953
1954 PitWriteCommand(0x34);
1955 PitWriteData(0, 0x00);
1956 PitWriteData(0, 0x00);
1957
1958 return TRUE;
1959 }
1960
1961 VOID BiosCleanup(VOID)
1962 {
1963 SMALL_RECT ConRect;
1964 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
1965
1966 PS2Cleanup();
1967
1968 /* Restore the old screen buffer */
1969 SetConsoleActiveScreenBuffer(BiosConsoleOutput);
1970
1971 /* Restore the original console size */
1972 GetConsoleScreenBufferInfo(BiosConsoleOutput, &ConsoleInfo);
1973 ConRect.Left = 0; // BiosSavedBufferInfo.srWindow.Left;
1974 // ConRect.Top = ConsoleInfo.dwCursorPosition.Y / (BiosSavedBufferInfo.srWindow.Bottom - BiosSavedBufferInfo.srWindow.Top + 1);
1975 // ConRect.Top *= (BiosSavedBufferInfo.srWindow.Bottom - BiosSavedBufferInfo.srWindow.Top + 1);
1976 ConRect.Top = ConsoleInfo.dwCursorPosition.Y;
1977 ConRect.Right = ConRect.Left + BiosSavedBufferInfo.srWindow.Right - BiosSavedBufferInfo.srWindow.Left;
1978 ConRect.Bottom = ConRect.Top + BiosSavedBufferInfo.srWindow.Bottom - BiosSavedBufferInfo.srWindow.Top ;
1979 /* See the following trick explanation in vga.c:VgaEnterTextMode() */
1980 SetConsoleScreenBufferSize(BiosConsoleOutput, BiosSavedBufferInfo.dwSize);
1981 SetConsoleWindowInfo(BiosConsoleOutput, TRUE, &ConRect);
1982 // SetConsoleWindowInfo(BiosConsoleOutput, TRUE, &BiosSavedBufferInfo.srWindow);
1983 SetConsoleScreenBufferSize(BiosConsoleOutput, BiosSavedBufferInfo.dwSize);
1984
1985 /* Restore the original cursor shape */
1986 SetConsoleCursorInfo(BiosConsoleOutput, &BiosSavedCursorInfo);
1987
1988 /* Restore the original input and output console modes */
1989 SetConsoleMode(BiosConsoleOutput, BiosSavedConOutMode);
1990 SetConsoleMode(BiosConsoleInput , BiosSavedConInMode );
1991
1992 /* Close the console handles */
1993 if (BiosConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleOutput);
1994 if (BiosConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(BiosConsoleInput);
1995 }
1996
1997 VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
1998 {
1999 switch (IrqNumber)
2000 {
2001 /* PIT IRQ */
2002 case 0:
2003 {
2004 /* Perform the system timer interrupt */
2005 EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT);
2006 break;
2007 }
2008
2009 /* Keyboard IRQ */
2010 case 1:
2011 {
2012 BYTE ScanCode, VirtualKey;
2013 WORD Character;
2014
2015 /* Get the scan code and virtual key code */
2016 ScanCode = IOReadB(PS2_DATA_PORT);
2017 VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
2018
2019 /* Check if this is a key press or release */
2020 if (!(ScanCode & (1 << 7)))
2021 {
2022 /* Key press */
2023 if (VirtualKey == VK_NUMLOCK ||
2024 VirtualKey == VK_CAPITAL ||
2025 VirtualKey == VK_SCROLL ||
2026 VirtualKey == VK_INSERT)
2027 {
2028 /* For toggle keys, toggle the lowest bit in the keyboard map */
2029 BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
2030 }
2031
2032 /* Set the highest bit */
2033 BiosKeyboardMap[VirtualKey] |= (1 << 7);
2034
2035 /* Find out which character this is */
2036 Character = 0;
2037 if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0)
2038 {
2039 /* Not ASCII */
2040 Character = 0;
2041 }
2042
2043 /* Push it onto the BIOS keyboard queue */
2044 BiosKbdBufferPush(MAKEWORD(Character, ScanCode));
2045 }
2046 else
2047 {
2048 /* Key release, unset the highest bit */
2049 BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
2050 }
2051
2052 /* Clear the keyboard flags */
2053 Bda->KeybdShiftFlags = 0;
2054
2055 /* Set the appropriate flags based on the state */
2056 if (BiosKeyboardMap[VK_RSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RSHIFT;
2057 if (BiosKeyboardMap[VK_LSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT;
2058 if (BiosKeyboardMap[VK_CONTROL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CTRL;
2059 if (BiosKeyboardMap[VK_MENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_ALT;
2060 if (BiosKeyboardMap[VK_SCROLL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL_ON;
2061 if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK_ON;
2062 if (BiosKeyboardMap[VK_CAPITAL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK_ON;
2063 if (BiosKeyboardMap[VK_INSERT] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT_ON;
2064 if (BiosKeyboardMap[VK_RMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RALT;
2065 if (BiosKeyboardMap[VK_LMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LALT;
2066 if (BiosKeyboardMap[VK_SNAPSHOT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SYSRQ;
2067 if (BiosKeyboardMap[VK_PAUSE] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_PAUSE;
2068 if (BiosKeyboardMap[VK_SCROLL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL;
2069 if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK;
2070 if (BiosKeyboardMap[VK_CAPITAL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK;
2071 if (BiosKeyboardMap[VK_INSERT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT;
2072
2073 break;
2074 }
2075 }
2076
2077 /* Send End-of-Interrupt to the PIC */
2078 if (IrqNumber >= 8) IOWriteB(PIC_SLAVE_CMD, PIC_OCW2_EOI);
2079 IOWriteB(PIC_MASTER_CMD, PIC_OCW2_EOI);
2080 }
2081
2082 /* EOF */