2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
22 #include "registers.h"
24 /* MACROS *********************************************************************/
27 // These macros are defined for ease-of-use of some VGA I/O ports
28 // whose addresses depend whether we are in Monochrome or Colour mode.
30 #define VGA_INSTAT1_READ Bda->CrtBasePort + 6 // VGA_INSTAT1_READ_MONO or VGA_INSTAT1_READ_COLOR
31 #define VGA_CRTC_INDEX Bda->CrtBasePort // VGA_CRTC_INDEX_MONO or VGA_CRTC_INDEX_COLOR
32 #define VGA_CRTC_DATA Bda->CrtBasePort + 1 // VGA_CRTC_DATA_MONO or VGA_CRTC_DATA_COLOR
34 /* PRIVATE VARIABLES **********************************************************/
37 static BYTE BiosKeyboardMap
[256];
38 static HANDLE BiosConsoleInput
= INVALID_HANDLE_VALUE
;
39 static HANDLE BiosConsoleOutput
= INVALID_HANDLE_VALUE
;
40 static CONSOLE_SCREEN_BUFFER_INFO BiosSavedBufferInfo
;
43 * VGA Register Configurations for BIOS Video Modes
44 * The configurations come from DosBox.
46 static VGA_REGISTERS VideoMode_40x25_text
=
48 /* Miscellaneous Register */
51 /* Sequencer Registers */
52 {0x00, 0x08, 0x03, 0x00, 0x07},
55 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0xA0, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
56 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x1F, 0x96, 0xB9, 0xA3,
60 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF},
63 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
64 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}
67 static VGA_REGISTERS VideoMode_80x25_text
=
69 /* Miscellaneous Register */
72 /* Sequencer Registers */
73 {0x00, 0x00, 0x03, 0x00, 0x07},
76 {0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x4F, 0x0D, 0x0E,
77 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
81 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x0F, 0xFF},
84 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
85 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00}
88 static VGA_REGISTERS VideoMode_320x200_4color
=
90 /* Miscellaneous Register */
93 /* Sequencer Registers */
94 {0x00, 0x09, 0x00, 0x00, 0x02},
97 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xA2,
102 {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0F, 0x0F, 0xFF},
105 {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
106 0x14, 0x15, 0x16, 0x17, 0x01, 0x00, 0x0F, 0x00, 0x00}
109 static VGA_REGISTERS VideoMode_640x200_2color
=
111 /* Miscellaneous Register */
114 /* Sequencer Registers */
115 {0x00, 0x09, 0x0F, 0x00, 0x02},
118 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC1, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xC2,
123 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0xFF},
126 {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
127 0x17, 0x17, 0x17, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00}
130 static VGA_REGISTERS VideoMode_320x200_16color
=
132 /* Miscellaneous Register */
135 /* Sequencer Registers */
136 {0x00, 0x09, 0x0F, 0x00, 0x02},
139 {0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xE3,
144 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
147 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
148 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
151 static VGA_REGISTERS VideoMode_640x200_16color
=
153 /* Miscellaneous Register */
156 /* Sequencer Registers */
157 {0x00, 0x01, 0x0F, 0x00, 0x02},
160 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0xC0, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xE3,
165 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
168 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
169 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
172 static VGA_REGISTERS VideoMode_640x350_16color
=
174 /* Miscellaneous Register */
177 /* Sequencer Registers */
178 {0x00, 0x01, 0x0F, 0x00, 0x02},
181 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x40, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x83, 0x85, 0x5D, 0x28, 0x0F, 0x63, 0xBA, 0xE3,
186 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
189 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
190 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
193 static VGA_REGISTERS VideoMode_640x480_2color
=
195 /* Miscellaneous Register */
198 /* Sequencer Registers */
199 {0x00, 0x01, 0x0F, 0x00, 0x02},
202 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
203 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xC3,
207 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
210 {0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
211 0x3F, 0x3F, 0x3F, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
214 static VGA_REGISTERS VideoMode_640x480_16color
=
216 /* Miscellaneous Register */
219 /* Sequencer Registers */
220 {0x00, 0x01, 0x0F, 0x00, 0x02},
223 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3,
228 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
231 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
232 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00}
235 static VGA_REGISTERS VideoMode_320x200_256color
=
237 /* Miscellaneous Register */
240 /* Sequencer Registers */
241 {0x00, 0x01, 0x0F, 0x00, 0x0E},
244 {0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
249 {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF},
252 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
253 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00}
256 /* See http://wiki.osdev.org/Drawing_In_Protected_Mode#Locating_Video_Memory */
257 static PVGA_REGISTERS VideoModes
[BIOS_MAX_VIDEO_MODE
+ 1] =
259 &VideoMode_40x25_text
, /* Mode 00h */ // 16 color (mono)
260 &VideoMode_40x25_text
, /* Mode 01h */ // 16 color
261 &VideoMode_80x25_text
, /* Mode 02h */ // 16 color (mono)
262 &VideoMode_80x25_text
, /* Mode 03h */ // 16 color
263 &VideoMode_320x200_4color
, /* Mode 04h */ // 4 color
264 &VideoMode_320x200_4color
, /* Mode 05h */ // same (m)
265 &VideoMode_640x200_2color
, /* Mode 06h */ // 640*200 2 color
266 NULL
, /* Mode 07h */ // MDA monochrome text 80*25
267 NULL
, /* Mode 08h */ // PCjr
268 NULL
, /* Mode 09h */ // PCjr
269 NULL
, /* Mode 0Ah */ // PCjr
270 NULL
, /* Mode 0Bh */ // Reserved
271 NULL
, /* Mode 0Ch */ // Reserved
272 &VideoMode_320x200_16color
, /* Mode 0Dh */ // EGA 320*200 16 color
273 &VideoMode_640x200_16color
, /* Mode 0Eh */ // EGA 640*200 16 color
274 NULL
, /* Mode 0Fh */ // EGA 640*350 mono
275 &VideoMode_640x350_16color
, /* Mode 10h */ // EGA 640*350 HiRes 16 color
276 &VideoMode_640x480_2color
, /* Mode 11h */ // VGA 640*480 mono
277 &VideoMode_640x480_16color
, /* Mode 12h */ // VGA
278 &VideoMode_320x200_256color
, /* Mode 13h */ // VGA
281 // FIXME: Are they computable with the previous data ??
282 // Values taken from DosBox
283 static WORD VideoModePageSize
[BIOS_MAX_VIDEO_MODE
+ 1] =
285 0x0800, 0x0800, 0x1000, 0x1000,
286 0x4000, 0x4000, 0x4000, 0x1000,
287 0x0000, 0x0000, 0x0000, 0x0000,
288 0x0000, 0x2000, 0x4000, 0x8000,
289 0x8000, 0xA000, 0xA000, 0x2000
292 /* PRIVATE FUNCTIONS **********************************************************/
294 static BOOLEAN
BiosKbdBufferPush(WORD Data
)
296 /* Get the location of the element after the tail */
297 WORD NextElement
= Bda
->KeybdBufferTail
+ sizeof(WORD
);
299 /* Wrap it around if it's at or beyond the end */
300 if (NextElement
>= Bda
->KeybdBufferEnd
) NextElement
= Bda
->KeybdBufferStart
;
302 /* If it's full, fail */
303 if (NextElement
== Bda
->KeybdBufferHead
) return FALSE
;
305 /* Put the value in the queue */
306 *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferTail
)) = Data
;
307 Bda
->KeybdBufferTail
+= sizeof(WORD
);
309 /* Check if we are at, or have passed, the end of the buffer */
310 if (Bda
->KeybdBufferTail
>= Bda
->KeybdBufferEnd
)
312 /* Return it to the beginning */
313 Bda
->KeybdBufferTail
= Bda
->KeybdBufferStart
;
320 static BOOLEAN
BiosKbdBufferTop(LPWORD Data
)
322 /* If it's empty, fail */
323 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
325 /* Otherwise, get the value and return success */
326 *Data
= *((LPWORD
)((ULONG_PTR
)Bda
+ Bda
->KeybdBufferHead
));
331 static BOOLEAN
BiosKbdBufferPop(VOID
)
333 /* If it's empty, fail */
334 if (Bda
->KeybdBufferHead
== Bda
->KeybdBufferTail
) return FALSE
;
336 /* Remove the value from the queue */
337 Bda
->KeybdBufferHead
+= sizeof(WORD
);
339 /* Check if we are at, or have passed, the end of the buffer */
340 if (Bda
->KeybdBufferHead
>= Bda
->KeybdBufferEnd
)
342 /* Return it to the beginning */
343 Bda
->KeybdBufferHead
= Bda
->KeybdBufferStart
;
350 static VOID
BiosReadWindow(LPWORD Buffer
, SMALL_RECT Rectangle
, BYTE Page
)
355 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Page
* Bda
->VideoPageSize
);
357 for (i
= Rectangle
.Top
; i
<= Rectangle
.Bottom
; i
++)
359 for (j
= Rectangle
.Left
; j
<= Rectangle
.Right
; j
++)
361 /* Read from video memory */
362 VgaReadMemory(VideoAddress
+ (i
* Bda
->ScreenColumns
+ j
) * sizeof(WORD
),
366 /* Write the data to the buffer in row order */
367 Buffer
[Counter
++] = Character
;
372 static VOID
BiosWriteWindow(LPWORD Buffer
, SMALL_RECT Rectangle
, BYTE Page
)
377 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Page
* Bda
->VideoPageSize
);
379 for (i
= Rectangle
.Top
; i
<= Rectangle
.Bottom
; i
++)
381 for (j
= Rectangle
.Left
; j
<= Rectangle
.Right
; j
++)
383 Character
= Buffer
[Counter
++];
385 /* Write to video memory */
386 VgaWriteMemory(VideoAddress
+ (i
* Bda
->ScreenColumns
+ j
) * sizeof(WORD
),
393 static BOOLEAN
VgaSetRegisters(PVGA_REGISTERS Registers
)
397 if (Registers
== NULL
) return FALSE
;
399 /* Disable interrupts */
403 * Set the CRT base address according to the selected mode,
404 * monochrome or color. The following macros:
405 * VGA_INSTAT1_READ, VGA_CRTC_INDEX and VGA_CRTC_DATA are then
406 * used to access the correct VGA I/O ports.
408 Bda
->CrtBasePort
= (Registers
->Misc
& 0x01) ? VGA_CRTC_INDEX_COLOR
409 : VGA_CRTC_INDEX_MONO
;
411 /* Write the misc register */
412 VgaWritePort(VGA_MISC_WRITE
, Registers
->Misc
);
414 /* Synchronous reset on */
415 VgaWritePort(VGA_SEQ_INDEX
, VGA_SEQ_RESET_REG
);
416 VgaWritePort(VGA_SEQ_DATA
, VGA_SEQ_RESET_AR
);
418 /* Write the sequencer registers */
419 for (i
= 1; i
< VGA_SEQ_MAX_REG
; i
++)
421 VgaWritePort(VGA_SEQ_INDEX
, i
);
422 VgaWritePort(VGA_SEQ_DATA
, Registers
->Sequencer
[i
]);
425 /* Synchronous reset off */
426 VgaWritePort(VGA_SEQ_INDEX
, VGA_SEQ_RESET_REG
);
427 VgaWritePort(VGA_SEQ_DATA
, VGA_SEQ_RESET_SR
| VGA_SEQ_RESET_AR
);
429 /* Unlock CRTC registers 0-7 */
430 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_END_HORZ_BLANKING_REG
);
431 VgaWritePort(VGA_CRTC_DATA
, VgaReadPort(VGA_CRTC_DATA
) | 0x80);
432 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_VERT_RETRACE_END_REG
);
433 VgaWritePort(VGA_CRTC_DATA
, VgaReadPort(VGA_CRTC_DATA
) & ~0x80);
434 // Make sure they remain unlocked
435 Registers
->CRT
[VGA_CRTC_END_HORZ_BLANKING_REG
] |= 0x80;
436 Registers
->CRT
[VGA_CRTC_VERT_RETRACE_END_REG
] &= ~0x80;
438 /* Write the CRTC registers */
439 for (i
= 0; i
< VGA_CRTC_MAX_REG
; i
++)
441 VgaWritePort(VGA_CRTC_INDEX
, i
);
442 VgaWritePort(VGA_CRTC_DATA
, Registers
->CRT
[i
]);
445 /* Write the GC registers */
446 for (i
= 0; i
< VGA_GC_MAX_REG
; i
++)
448 VgaWritePort(VGA_GC_INDEX
, i
);
449 VgaWritePort(VGA_GC_DATA
, Registers
->Graphics
[i
]);
452 /* Write the AC registers */
453 for (i
= 0; i
< VGA_AC_MAX_REG
; i
++)
455 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
456 VgaWritePort(VGA_AC_INDEX
, i
);
457 VgaWritePort(VGA_AC_WRITE
, Registers
->Attribute
[i
]);
460 /* Set the PEL mask */
461 VgaWritePort(VGA_DAC_MASK
, 0xFF);
463 /* Enable screen and disable palette access */
464 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
465 VgaWritePort(VGA_AC_INDEX
, 0x20);
467 /* Enable interrupts */
473 /* PUBLIC FUNCTIONS ***********************************************************/
475 BYTE
BiosGetVideoMode(VOID
)
477 return Bda
->VideoMode
;
480 BOOLEAN
BiosSetVideoMode(BYTE ModeNumber
)
486 PVGA_REGISTERS VgaMode
= VideoModes
[ModeNumber
];
488 DPRINT1("Switching to mode %Xh; VgaMode = 0x%p\n", ModeNumber
, VgaMode
);
490 if (!VgaSetRegisters(VgaMode
)) return FALSE
;
492 // /* Disable screen and enable palette access */
493 // VgaReadPort(VGA_INSTAT1_READ); // Put the AC register into index state
494 // VgaWritePort(VGA_AC_INDEX, 0x00);
496 if ((ModeNumber
== 0x0D) || (ModeNumber
== 0x0E) || (ModeNumber
== 0x10))
499 extern CONST COLORREF EgaPalette
[VGA_MAX_COLORS
/ 4];
500 for (i
= 0; i
< sizeof(EgaPalette
)/sizeof(EgaPalette
[0]); i
++)
502 VgaWritePort(VGA_DAC_WRITE_INDEX
, i
);
503 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetRValue(EgaPalette
[i
])));
504 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetGValue(EgaPalette
[i
])));
505 VgaWritePort(VGA_DAC_DATA
, VGA_COLOR_TO_DAC(GetBValue(EgaPalette
[i
])));
510 /* Reset the palette */
514 // /* Enable screen and disable palette access */
515 // VgaReadPort(VGA_INSTAT1_READ); // Put the AC register into index state
516 // VgaWritePort(VGA_AC_INDEX, 0x20);
518 // Bda->CrtModeControl;
519 // Bda->CrtColorPaletteMask;
523 /* Update the values in the BDA */
524 Bda
->VideoMode
= ModeNumber
;
525 Bda
->VideoPageSize
= VideoModePageSize
[ModeNumber
];
527 Bda
->VideoPageOffset
= Bda
->VideoPage
* Bda
->VideoPageSize
;
529 /* Set the start address in the CRTC */
530 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_START_ADDR_LOW_REG
);
531 VgaWritePort(VGA_CRTC_DATA
, LOBYTE(Bda
->VideoPageOffset
));
532 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_START_ADDR_HIGH_REG
);
533 VgaWritePort(VGA_CRTC_DATA
, HIBYTE(Bda
->VideoPageOffset
));
535 /* Get the character height */
536 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_MAX_SCAN_LINE_REG
);
537 Bda
->CharacterHeight
= 1 + (VgaReadPort(VGA_CRTC_DATA
) & 0x1F);
539 Resolution
= VgaGetDisplayResolution();
540 Bda
->ScreenColumns
= Resolution
.X
;
541 Bda
->ScreenRows
= Resolution
.Y
- 1;
543 /* Set cursor position for each page */
544 for (Page
= 0; Page
< BIOS_MAX_PAGES
; ++Page
)
545 BiosSetCursorPosition(0, 0, Page
);
550 BOOLEAN
BiosSetVideoPage(BYTE PageNumber
)
554 /* Check if the page exists */
555 if (PageNumber
>= BIOS_MAX_PAGES
) return FALSE
;
557 /* Check if this is the same page */
558 if (PageNumber
== Bda
->VideoPage
) return TRUE
;
560 /* Update the values in the BDA */
561 Bda
->VideoPage
= PageNumber
;
562 Bda
->VideoPageOffset
= Bda
->VideoPage
* Bda
->VideoPageSize
;
564 /* Set the start address in the CRTC */
565 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_START_ADDR_LOW_REG
);
566 VgaWritePort(VGA_CRTC_DATA
, LOBYTE(Bda
->VideoPageOffset
));
567 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_START_ADDR_HIGH_REG
);
568 VgaWritePort(VGA_CRTC_DATA
, HIBYTE(Bda
->VideoPageOffset
));
571 * Get the cursor location (we don't update anything on the BIOS side
572 * but we update the cursor location on the VGA side).
574 BiosGetCursorPosition(&Row
, &Column
, PageNumber
);
575 BiosSetCursorPosition(Row
, Column
, PageNumber
);
580 BOOLEAN
BiosInitialize(VOID
)
582 /* Initialize the BDA */
583 Bda
= (PBIOS_DATA_AREA
)SEG_OFF_TO_PTR(BDA_SEGMENT
, 0);
584 Bda
->EquipmentList
= BIOS_EQUIPMENT_LIST
;
586 * Conventional memory size is 640 kB,
587 * see: http://webpages.charter.net/danrollins/techhelp/0184.HTM
588 * and see Ralf Brown: http://www.ctyme.com/intr/rb-0598.htm
589 * for more information.
591 Bda
->MemorySize
= 0x0280;
592 Bda
->KeybdBufferStart
= FIELD_OFFSET(BIOS_DATA_AREA
, KeybdBuffer
);
593 Bda
->KeybdBufferEnd
= Bda
->KeybdBufferStart
+ BIOS_KBD_BUFFER_SIZE
* sizeof(WORD
);
594 Bda
->KeybdBufferHead
= Bda
->KeybdBufferTail
= 0;
596 /* Initialize the 32-bit Interrupt system */
597 InitializeInt32(BIOS_SEGMENT
);
599 /* Register the BIOS 32-bit Interrupts */
600 RegisterInt32(BIOS_VIDEO_INTERRUPT
, BiosVideoService
);
601 RegisterInt32(BIOS_EQUIPMENT_INTERRUPT
, BiosEquipmentService
);
602 RegisterInt32(BIOS_MEMORY_SIZE
, BiosGetMemorySize
);
603 RegisterInt32(BIOS_MISC_INTERRUPT
, BiosMiscService
);
604 RegisterInt32(BIOS_KBD_INTERRUPT
, BiosKeyboardService
);
605 RegisterInt32(BIOS_TIME_INTERRUPT
, BiosTimeService
);
606 RegisterInt32(BIOS_SYS_TIMER_INTERRUPT
, BiosSystemTimerInterrupt
);
608 /* Some interrupts are in fact addresses to tables */
609 ((PDWORD
)BaseAddress
)[0x1D] = (DWORD
)NULL
;
610 ((PDWORD
)BaseAddress
)[0x1E] = (DWORD
)NULL
;
611 ((PDWORD
)BaseAddress
)[0x1F] = (DWORD
)NULL
;
613 ((PDWORD
)BaseAddress
)[0x41] = (DWORD
)NULL
;
614 ((PDWORD
)BaseAddress
)[0x43] = (DWORD
)NULL
;
615 ((PDWORD
)BaseAddress
)[0x44] = (DWORD
)NULL
;
616 ((PDWORD
)BaseAddress
)[0x46] = (DWORD
)NULL
;
617 ((PDWORD
)BaseAddress
)[0x48] = (DWORD
)NULL
;
618 ((PDWORD
)BaseAddress
)[0x49] = (DWORD
)NULL
;
620 /* Get the input handle to the real console, and check for success */
621 BiosConsoleInput
= CreateFileW(L
"CONIN$",
622 GENERIC_READ
| GENERIC_WRITE
,
623 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
628 if (BiosConsoleInput
== INVALID_HANDLE_VALUE
)
633 /* Get the output handle to the real console, and check for success */
634 BiosConsoleOutput
= CreateFileW(L
"CONOUT$",
635 GENERIC_READ
| GENERIC_WRITE
,
636 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
641 if (BiosConsoleOutput
== INVALID_HANDLE_VALUE
)
643 CloseHandle(BiosConsoleInput
);
647 /* Save the console screen buffer information */
648 if (!GetConsoleScreenBufferInfo(BiosConsoleOutput
, &BiosSavedBufferInfo
))
650 CloseHandle(BiosConsoleOutput
);
651 CloseHandle(BiosConsoleInput
);
656 if (!VgaInitialize(BiosConsoleOutput
))
658 CloseHandle(BiosConsoleOutput
);
659 CloseHandle(BiosConsoleInput
);
663 /* Update the cursor position */
664 BiosSetCursorPosition(BiosSavedBufferInfo
.dwCursorPosition
.Y
,
665 BiosSavedBufferInfo
.dwCursorPosition
.X
,
668 /* Set the console input mode */
669 SetConsoleMode(BiosConsoleInput
, ENABLE_MOUSE_INPUT
| ENABLE_PROCESSED_INPUT
);
672 PS2Initialize(BiosConsoleInput
);
674 /* Initialize the PIC */
675 PicWriteCommand(PIC_MASTER_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
676 PicWriteCommand(PIC_SLAVE_CMD
, PIC_ICW1
| PIC_ICW1_ICW4
);
678 /* Set the interrupt offsets */
679 PicWriteData(PIC_MASTER_DATA
, BIOS_PIC_MASTER_INT
);
680 PicWriteData(PIC_SLAVE_DATA
, BIOS_PIC_SLAVE_INT
);
682 /* Tell the master PIC there is a slave at IRQ 2 */
683 PicWriteData(PIC_MASTER_DATA
, 1 << 2);
684 PicWriteData(PIC_SLAVE_DATA
, 2);
686 /* Make sure the PIC is in 8086 mode */
687 PicWriteData(PIC_MASTER_DATA
, PIC_ICW4_8086
);
688 PicWriteData(PIC_SLAVE_DATA
, PIC_ICW4_8086
);
690 /* Clear the masks for both PICs */
691 PicWriteData(PIC_MASTER_DATA
, 0x00);
692 PicWriteData(PIC_SLAVE_DATA
, 0x00);
694 PitWriteCommand(0x34);
695 PitWriteData(0, 0x00);
696 PitWriteData(0, 0x00);
701 VOID
BiosCleanup(VOID
)
705 /* Restore the old screen buffer */
706 SetConsoleActiveScreenBuffer(BiosConsoleOutput
);
708 /* Restore the screen buffer size */
709 SetConsoleScreenBufferSize(BiosConsoleOutput
, BiosSavedBufferInfo
.dwSize
);
711 /* Close the console handles */
712 if (BiosConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(BiosConsoleOutput
);
713 if (BiosConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(BiosConsoleInput
);
716 WORD
BiosPeekCharacter(VOID
)
718 WORD CharacterData
= 0;
720 /* Get the key from the queue, but don't remove it */
721 if (BiosKbdBufferTop(&CharacterData
)) return CharacterData
;
725 WORD
BiosGetCharacter(VOID
)
727 WORD CharacterData
= 0;
729 /* Check if there is a key available */
730 if (BiosKbdBufferTop(&CharacterData
))
732 /* A key was available, remove it from the queue */
737 /* No key available. Set the handler CF to repeat the BOP */
739 // CharacterData = 0xFFFF;
742 return CharacterData
;
745 VOID
BiosGetCursorPosition(PBYTE Row
, PBYTE Column
, BYTE Page
)
747 /* Make sure the selected video page is valid */
748 if (Page
>= BIOS_MAX_PAGES
) return;
750 /* Get the cursor location */
751 *Row
= HIBYTE(Bda
->CursorPosition
[Page
]);
752 *Column
= LOBYTE(Bda
->CursorPosition
[Page
]);
755 VOID
BiosSetCursorPosition(BYTE Row
, BYTE Column
, BYTE Page
)
757 /* Make sure the selected video page is valid */
758 if (Page
>= BIOS_MAX_PAGES
) return;
760 /* Update the position in the BDA */
761 Bda
->CursorPosition
[Page
] = MAKEWORD(Column
, Row
);
763 /* Check if this is the current video page */
764 if (Page
== Bda
->VideoPage
)
766 WORD Offset
= Row
* Bda
->ScreenColumns
+ Column
;
768 /* Modify the CRTC registers */
769 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_LOW_REG
);
770 VgaWritePort(VGA_CRTC_DATA
, LOBYTE(Offset
));
771 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_LOC_HIGH_REG
);
772 VgaWritePort(VGA_CRTC_DATA
, HIBYTE(Offset
));
776 BOOLEAN
BiosScrollWindow(INT Direction
,
778 SMALL_RECT Rectangle
,
784 WORD WindowWidth
= Rectangle
.Right
- Rectangle
.Left
+ 1;
785 WORD WindowHeight
= Rectangle
.Bottom
- Rectangle
.Top
+ 1;
786 DWORD WindowSize
= WindowWidth
* WindowHeight
;
788 /* Allocate a buffer for the window */
789 WindowData
= (LPWORD
)HeapAlloc(GetProcessHeap(),
791 WindowSize
* sizeof(WORD
));
792 if (WindowData
== NULL
) return FALSE
;
794 /* Read the window data */
795 BiosReadWindow(WindowData
, Rectangle
, Page
);
798 || (((Direction
== SCROLL_DIRECTION_UP
)
799 || (Direction
== SCROLL_DIRECTION_DOWN
))
800 && (Amount
>= WindowHeight
))
801 || (((Direction
== SCROLL_DIRECTION_LEFT
)
802 || (Direction
== SCROLL_DIRECTION_RIGHT
))
803 && (Amount
>= WindowWidth
)))
805 /* Fill the window */
806 for (i
= 0; i
< WindowSize
; i
++)
808 WindowData
[i
] = MAKEWORD(' ', FillAttribute
);
816 case SCROLL_DIRECTION_UP
:
818 RtlMoveMemory(WindowData
,
819 &WindowData
[WindowWidth
* Amount
],
820 (WindowSize
- WindowWidth
* Amount
) * sizeof(WORD
));
822 for (i
= 0; i
< Amount
* WindowWidth
; i
++)
824 WindowData
[WindowSize
- i
- 1] = MAKEWORD(' ', FillAttribute
);
830 case SCROLL_DIRECTION_DOWN
:
832 RtlMoveMemory(&WindowData
[WindowWidth
* Amount
],
834 (WindowSize
- WindowWidth
* Amount
) * sizeof(WORD
));
836 for (i
= 0; i
< Amount
* WindowWidth
; i
++)
838 WindowData
[i
] = MAKEWORD(' ', FillAttribute
);
846 // TODO: NOT IMPLEMENTED!
852 /* Write back the window data */
853 BiosWriteWindow(WindowData
, Rectangle
, Page
);
855 /* Free the window buffer */
856 HeapFree(GetProcessHeap(), 0, WindowData
);
861 VOID
BiosPrintCharacter(CHAR Character
, BYTE Attribute
, BYTE Page
)
863 WORD CharData
= MAKEWORD(Character
, Attribute
);
866 /* Make sure the page exists */
867 if (Page
>= BIOS_MAX_PAGES
) return;
869 /* Get the cursor location */
870 BiosGetCursorPosition(&Row
, &Column
, Page
);
872 if (Character
== '\a')
874 /* Bell control character */
875 // NOTE: We may use what the terminal emulator offers to us...
879 else if (Character
== '\b')
881 /* Backspace control character */
888 Column
= Bda
->ScreenColumns
- 1;
892 /* Erase the existing character */
893 CharData
= MAKEWORD(' ', Attribute
);
894 EmulatorWriteMemory(&EmulatorContext
,
895 TO_LINEAR(TEXT_VIDEO_SEG
,
896 Page
* Bda
->VideoPageSize
+
897 (Row
* Bda
->ScreenColumns
+ Column
) * sizeof(WORD
)),
901 else if (Character
== '\t')
903 /* Horizontal Tabulation control character */
907 BiosPrintCharacter(' ', Attribute
, Page
);
908 BiosGetCursorPosition(&Row
, &Column
, Page
);
909 } while (Column
% 8);
911 else if (Character
== '\n')
913 /* Line Feed control character */
916 else if (Character
== '\r')
918 /* Carriage Return control character */
923 /* Default character */
925 /* Write the character */
926 EmulatorWriteMemory(&EmulatorContext
,
927 TO_LINEAR(TEXT_VIDEO_SEG
,
928 Page
* Bda
->VideoPageSize
+
929 (Row
* Bda
->ScreenColumns
+ Column
) * sizeof(WORD
)),
933 /* Advance the cursor */
937 /* Check if it passed the end of the row */
938 if (Column
>= Bda
->ScreenColumns
)
940 /* Return to the first column and go to the next line */
945 /* Scroll the screen up if needed */
946 if (Row
> Bda
->ScreenRows
)
948 /* The screen must be scrolled up */
949 SMALL_RECT Rectangle
= { 0, 0, Bda
->ScreenColumns
- 1, Bda
->ScreenRows
};
951 BiosScrollWindow(SCROLL_DIRECTION_UP
,
960 /* Set the cursor position */
961 BiosSetCursorPosition(Row
, Column
, Page
);
964 VOID WINAPI
BiosVideoService(LPWORD Stack
)
971 BiosSetVideoMode(getAL());
976 /* Set Text-Mode Cursor Shape */
980 Bda
->CursorStartLine
= getCH();
981 Bda
->CursorEndLine
= getCL();
983 /* Modify the CRTC registers */
984 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_START_REG
);
985 VgaWritePort(VGA_CRTC_DATA
, Bda
->CursorStartLine
);
986 VgaWritePort(VGA_CRTC_INDEX
, VGA_CRTC_CURSOR_END_REG
);
987 VgaWritePort(VGA_CRTC_DATA
, Bda
->CursorEndLine
);
992 /* Set Cursor Position */
995 BiosSetCursorPosition(getDH(), getDL(), getBH());
999 /* Get Cursor Position */
1002 /* Make sure the selected video page exists */
1003 if (getBH() >= BIOS_MAX_PAGES
) break;
1005 /* Return the result */
1007 setCX(MAKEWORD(Bda
->CursorEndLine
, Bda
->CursorStartLine
));
1008 setDX(Bda
->CursorPosition
[getBH()]);
1012 /* Query Light Pen */
1016 * On modern BIOSes, this function returns 0
1017 * so that we can ignore the other registers.
1023 /* Select Active Display Page */
1026 BiosSetVideoPage(getAL());
1030 /* Scroll Window Up/Down */
1034 SMALL_RECT Rectangle
= { getCL(), getCH(), getDL(), getDH() };
1036 /* Call the internal function */
1037 BiosScrollWindow((getAH() == 0x06) ? SCROLL_DIRECTION_UP
1038 : SCROLL_DIRECTION_DOWN
,
1047 /* Read/Write Character From Cursor Position */
1052 WORD CharacterData
= MAKEWORD(getAL(), getBL());
1053 BYTE Page
= getBH();
1056 /* Check if the page exists */
1057 if (Page
>= BIOS_MAX_PAGES
) break;
1059 /* Find the offset of the character */
1060 Offset
= Page
* Bda
->VideoPageSize
+
1061 (HIBYTE(Bda
->CursorPosition
[Page
]) * Bda
->ScreenColumns
+
1062 LOBYTE(Bda
->CursorPosition
[Page
])) * 2;
1064 if (getAH() == 0x08)
1066 /* Read from the video memory */
1067 VgaReadMemory(TO_LINEAR(TEXT_VIDEO_SEG
, Offset
),
1068 (LPVOID
)&CharacterData
,
1071 /* Return the character in AX */
1072 setAX(CharacterData
);
1076 /* Write to video memory */
1077 VgaWriteMemory(TO_LINEAR(TEXT_VIDEO_SEG
, Offset
),
1078 (LPVOID
)&CharacterData
,
1079 (getBH() == 0x09) ? sizeof(WORD
) : sizeof(BYTE
));
1085 /* Teletype Output */
1088 BiosPrintCharacter(getAL(), getBL(), getBH());
1092 /* Get Current Video Mode */
1095 setAX(MAKEWORD(Bda
->VideoMode
, Bda
->ScreenColumns
));
1096 setBX(MAKEWORD(getBL(), Bda
->VideoPage
));
1100 /* Palette Control */
1105 /* Set Single Palette Register */
1108 /* Write the index */
1109 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1110 VgaWritePort(VGA_AC_INDEX
, getBL());
1112 /* Write the data */
1113 VgaWritePort(VGA_AC_WRITE
, getBH());
1115 /* Enable screen and disable palette access */
1116 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1117 VgaWritePort(VGA_AC_INDEX
, 0x20);
1121 /* Set Overscan Color */
1124 /* Write the index */
1125 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1126 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1128 /* Write the data */
1129 VgaWritePort(VGA_AC_WRITE
, getBH());
1131 /* Enable screen and disable palette access */
1132 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1133 VgaWritePort(VGA_AC_INDEX
, 0x20);
1137 /* Set All Palette Registers */
1141 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1143 /* Set the palette registers */
1144 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1146 /* Write the index */
1147 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1148 VgaWritePort(VGA_AC_INDEX
, i
);
1150 /* Write the data */
1151 VgaWritePort(VGA_AC_WRITE
, Buffer
[i
]);
1154 /* Set the overscan register */
1155 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1156 VgaWritePort(VGA_AC_WRITE
, Buffer
[VGA_AC_PAL_F_REG
+ 1]);
1158 /* Enable screen and disable palette access */
1159 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1160 VgaWritePort(VGA_AC_INDEX
, 0x20);
1164 /* Get Single Palette Register */
1167 /* Write the index */
1168 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1169 VgaWritePort(VGA_AC_INDEX
, getBL());
1172 setBH(VgaReadPort(VGA_AC_READ
));
1174 /* Enable screen and disable palette access */
1175 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1176 VgaWritePort(VGA_AC_INDEX
, 0x20);
1180 /* Get Overscan Color */
1183 /* Write the index */
1184 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1185 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1188 setBH(VgaReadPort(VGA_AC_READ
));
1190 /* Enable screen and disable palette access */
1191 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1192 VgaWritePort(VGA_AC_INDEX
, 0x20);
1196 /* Get All Palette Registers */
1200 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1202 /* Get the palette registers */
1203 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1205 /* Write the index */
1206 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1207 VgaWritePort(VGA_AC_INDEX
, i
);
1210 Buffer
[i
] = VgaReadPort(VGA_AC_READ
);
1213 /* Get the overscan register */
1214 VgaWritePort(VGA_AC_INDEX
, VGA_AC_OVERSCAN_REG
);
1215 Buffer
[VGA_AC_PAL_F_REG
+ 1] = VgaReadPort(VGA_AC_READ
);
1217 /* Enable screen and disable palette access */
1218 VgaReadPort(VGA_INSTAT1_READ
); // Put the AC register into index state
1219 VgaWritePort(VGA_AC_INDEX
, 0x20);
1223 /* Set Individual DAC Register */
1226 /* Write the index */
1227 // Certainly in BL and not in BX as said by Ralf Brown...
1228 VgaWritePort(VGA_DAC_WRITE_INDEX
, getBL());
1230 /* Write the data in this order: Red, Green, Blue */
1231 VgaWritePort(VGA_DAC_DATA
, getDH());
1232 VgaWritePort(VGA_DAC_DATA
, getCH());
1233 VgaWritePort(VGA_DAC_DATA
, getCL());
1238 /* Set Block of DAC Registers */
1242 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1244 /* Write the index */
1245 // Certainly in BL and not in BX as said by Ralf Brown...
1246 VgaWritePort(VGA_DAC_WRITE_INDEX
, getBL());
1248 for (i
= 0; i
< getCX(); i
++)
1250 /* Write the data in this order: Red, Green, Blue */
1251 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1252 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1253 VgaWritePort(VGA_DAC_DATA
, *Buffer
++);
1259 /* Get Individual DAC Register */
1262 /* Write the index */
1263 VgaWritePort(VGA_DAC_READ_INDEX
, getBL());
1265 /* Read the data in this order: Red, Green, Blue */
1266 setDH(VgaReadPort(VGA_DAC_DATA
));
1267 setCH(VgaReadPort(VGA_DAC_DATA
));
1268 setCL(VgaReadPort(VGA_DAC_DATA
));
1273 /* Get Block of DAC Registers */
1277 LPBYTE Buffer
= SEG_OFF_TO_PTR(getES(), getDX());
1279 /* Write the index */
1280 // Certainly in BL and not in BX as said by Ralf Brown...
1281 VgaWritePort(VGA_DAC_READ_INDEX
, getBL());
1283 for (i
= 0; i
< getCX(); i
++)
1285 /* Write the data in this order: Red, Green, Blue */
1286 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1287 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1288 *Buffer
++ = VgaReadPort(VGA_DAC_DATA
);
1296 DPRINT1("BIOS Palette Control Sub-command AL = 0x%02X NOT IMPLEMENTED\n",
1308 SMALL_RECT Rectangle
= { getCL(), getCH(), getDL(), getDH() };
1310 /* Call the internal function */
1311 BiosScrollWindow(getBL(),
1320 /* Display combination code */
1325 case 0x00: /* Get Display combiantion code */
1326 setAX(MAKEWORD(0x1A, 0x1A));
1327 setBX(MAKEWORD(0x08, 0x00)); /* VGA w/ color analog display */
1329 case 0x01: /* Set Display combination code */
1330 DPRINT1("Set Display combination code - Unsupported\n");
1340 DPRINT1("BIOS Function INT 10h, AH = 0x%02X NOT IMPLEMENTED\n",
1346 VOID WINAPI
BiosEquipmentService(LPWORD Stack
)
1348 /* Return the equipment list */
1349 setAX(Bda
->EquipmentList
);
1352 VOID WINAPI
BiosGetMemorySize(LPWORD Stack
)
1354 /* Return the conventional memory size in kB, typically 640 kB */
1355 setAX(Bda
->MemorySize
);
1358 VOID WINAPI
BiosMiscService(LPWORD Stack
)
1362 /* Copy Extended Memory */
1365 DWORD Count
= (DWORD
)getCX() * 2;
1366 PFAST486_GDT_ENTRY Gdt
= (PFAST486_GDT_ENTRY
)SEG_OFF_TO_PTR(getES(), getSI());
1367 DWORD SourceBase
= Gdt
[2].Base
+ (Gdt
[2].BaseMid
<< 16) + (Gdt
[2].BaseHigh
<< 24);
1368 DWORD SourceLimit
= Gdt
[2].Limit
+ (Gdt
[2].LimitHigh
<< 16);
1369 DWORD DestBase
= Gdt
[3].Base
+ (Gdt
[3].BaseMid
<< 16) + (Gdt
[3].BaseHigh
<< 24);
1370 DWORD DestLimit
= Gdt
[3].Limit
+ (Gdt
[3].LimitHigh
<< 16);
1372 /* Check for flags */
1373 if (Gdt
[2].Granularity
) SourceLimit
= (SourceLimit
<< 12) | 0xFFF;
1374 if (Gdt
[3].Granularity
) DestLimit
= (DestLimit
<< 12) | 0xFFF;
1376 if ((Count
> SourceLimit
) || (Count
> DestLimit
))
1379 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_CF
;
1385 RtlMoveMemory((PVOID
)((ULONG_PTR
)BaseAddress
+ DestBase
),
1386 (PVOID
)((ULONG_PTR
)BaseAddress
+ SourceBase
),
1389 setAX(ERROR_SUCCESS
);
1390 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1394 /* Get Extended Memory Size */
1397 /* Return the number of KB of RAM after 1 MB */
1398 setAX((MAX_ADDRESS
- 0x100000) / 1024);
1401 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_CF
;
1408 DPRINT1("BIOS Function INT 15h, AH = 0x%02X NOT IMPLEMENTED\n",
1414 VOID WINAPI
BiosKeyboardService(LPWORD Stack
)
1418 /* Wait for keystroke and read */
1420 /* Wait for extended keystroke and read */
1421 case 0x10: // FIXME: Temporarily do the same as INT 16h, 00h
1423 /* Read the character (and wait if necessary) */
1424 setAX(BiosGetCharacter());
1428 /* Get keystroke status */
1430 /* Get extended keystroke status */
1431 case 0x11: // FIXME: Temporarily do the same as INT 16h, 01h
1433 WORD Data
= BiosPeekCharacter();
1437 /* There is a character, clear ZF and return it */
1438 Stack
[STACK_FLAGS
] &= ~EMULATOR_FLAG_ZF
;
1443 /* No character, set ZF */
1444 Stack
[STACK_FLAGS
] |= EMULATOR_FLAG_ZF
;
1450 /* Get shift status */
1453 /* Return the lower byte of the keyboard shift status word */
1454 setAL(LOBYTE(Bda
->KeybdShiftFlags
));
1461 DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
1465 /* Push keystroke */
1468 /* Return 0 if success, 1 if failure */
1469 setAL(BiosKbdBufferPush(getCX()) == FALSE
);
1473 /* Get extended shift status */
1477 * Be careful! The returned word is similar to Bda->KeybdShiftFlags
1478 * but the high byte is organized differently:
1479 * the bytes 2 and 3 of the high byte are not the same...
1481 WORD KeybdShiftFlags
= (Bda
->KeybdShiftFlags
& 0xF3FF);
1483 /* Return the extended keyboard shift status word */
1484 setAX(KeybdShiftFlags
);
1490 DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
1496 VOID WINAPI
BiosTimeService(LPWORD Stack
)
1502 /* Set AL to 1 if midnight had passed, 0 otherwise */
1503 setAL(Bda
->MidnightPassed
? 0x01 : 0x00);
1505 /* Return the tick count in CX:DX */
1506 setCX(HIWORD(Bda
->TickCounter
));
1507 setDX(LOWORD(Bda
->TickCounter
));
1509 /* Reset the midnight flag */
1510 Bda
->MidnightPassed
= FALSE
;
1517 /* Set the tick count to CX:DX */
1518 Bda
->TickCounter
= MAKELONG(getDX(), getCX());
1520 /* Reset the midnight flag */
1521 Bda
->MidnightPassed
= FALSE
;
1528 DPRINT1("BIOS Function INT 1Ah, AH = 0x%02X NOT IMPLEMENTED\n",
1534 VOID WINAPI
BiosSystemTimerInterrupt(LPWORD Stack
)
1536 /* Increase the system tick count */
1540 VOID
BiosHandleIrq(BYTE IrqNumber
, LPWORD Stack
)
1547 /* Perform the system timer interrupt */
1548 EmulatorInterrupt(BIOS_SYS_TIMER_INTERRUPT
);
1555 BYTE ScanCode
, VirtualKey
;
1558 /* Get the scan code and virtual key code */
1559 ScanCode
= PS2ReadPort(PS2_DATA_PORT
);
1560 VirtualKey
= MapVirtualKey(ScanCode
& 0x7F, MAPVK_VSC_TO_VK
);
1562 /* Check if this is a key press or release */
1563 if (!(ScanCode
& (1 << 7)))
1566 if (VirtualKey
== VK_NUMLOCK
||
1567 VirtualKey
== VK_CAPITAL
||
1568 VirtualKey
== VK_SCROLL
||
1569 VirtualKey
== VK_INSERT
)
1571 /* For toggle keys, toggle the lowest bit in the keyboard map */
1572 BiosKeyboardMap
[VirtualKey
] ^= ~(1 << 0);
1575 /* Set the highest bit */
1576 BiosKeyboardMap
[VirtualKey
] |= (1 << 7);
1578 /* Find out which character this is */
1580 if (ToAscii(VirtualKey
, ScanCode
, BiosKeyboardMap
, &Character
, 0) == 0)
1586 /* Push it onto the BIOS keyboard queue */
1587 BiosKbdBufferPush(MAKEWORD(Character
, ScanCode
));
1591 /* Key release, unset the highest bit */
1592 BiosKeyboardMap
[VirtualKey
] &= ~(1 << 7);
1595 /* Clear the keyboard flags */
1596 Bda
->KeybdShiftFlags
= 0;
1598 /* Set the appropriate flags based on the state */
1599 if (BiosKeyboardMap
[VK_RSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RSHIFT
;
1600 if (BiosKeyboardMap
[VK_LSHIFT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LSHIFT
;
1601 if (BiosKeyboardMap
[VK_CONTROL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CTRL
;
1602 if (BiosKeyboardMap
[VK_MENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_ALT
;
1603 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL_ON
;
1604 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK_ON
;
1605 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK_ON
;
1606 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 0)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT_ON
;
1607 if (BiosKeyboardMap
[VK_RMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_RALT
;
1608 if (BiosKeyboardMap
[VK_LMENU
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_LALT
;
1609 if (BiosKeyboardMap
[VK_SNAPSHOT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SYSRQ
;
1610 if (BiosKeyboardMap
[VK_PAUSE
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_PAUSE
;
1611 if (BiosKeyboardMap
[VK_SCROLL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_SCROLL
;
1612 if (BiosKeyboardMap
[VK_NUMLOCK
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_NUMLOCK
;
1613 if (BiosKeyboardMap
[VK_CAPITAL
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_CAPSLOCK
;
1614 if (BiosKeyboardMap
[VK_INSERT
] & (1 << 7)) Bda
->KeybdShiftFlags
|= BDA_KBDFLAG_INSERT
;
1620 /* Send End-of-Interrupt to the PIC */
1621 if (IrqNumber
>= 8) PicWriteCommand(PIC_SLAVE_CMD
, PIC_OCW2_EOI
);
1622 PicWriteCommand(PIC_MASTER_CMD
, PIC_OCW2_EOI
);