3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: display.c,v 1.7 2003/08/24 11:58:16 dwelch Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: ntoskrnl/hal/x86/display.c
24 * PURPOSE: Blue screen display
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
32 * So, who owns the physical display and is allowed to write to it?
34 * In MS NT, upon boot HAL owns the display. Somewhere in the boot
35 * sequence (haven't figured out exactly where or by who), some
36 * component calls HalAcquireDisplayOwnership. From that moment on,
37 * the display is owned by that component and is switched to graphics
38 * mode. The display is not supposed to return to text mode, except
39 * in case of a bug check. The bug check will call HalDisplayString
40 * to output a string to the text screen. HAL will notice that it
41 * currently doesn't own the display and will re-take ownership, by
42 * calling the callback function passed to HalAcquireDisplayOwnership.
43 * After the bugcheck, execution is halted. So, under NT, the only
44 * possible sequence of display modes is text mode -> graphics mode ->
45 * text mode (the latter hopefully happening very infrequently).
47 * Things are a little bit different in the current state of ReactOS.
48 * We want to have a functional interactive text mode. We should be
49 * able to switch from text mode to graphics mode when a GUI app is
50 * started and switch back to text mode when it's finished. Then, when
51 * another GUI app is started, another switch to and from graphics mode
52 * is possible. Also, when the system bugchecks in graphics mode we want
53 * to switch back to text mode to show the registers and stack trace.
54 * Last but not least, HalDisplayString is used a lot more in ReactOS,
55 * e.g. to print debug messages when the /DEBUGPORT=SCREEN boot option
57 * 3 Components are involved in Reactos: HAL, BLUE.SYS and VIDEOPRT.SYS.
58 * As in NT, on boot HAL owns the display. When entering the text mode
59 * command interpreter, BLUE.SYS kicks in. It will write directly to the
60 * screen, more or less behind HALs back.
61 * When a GUI app is started, WIN32K.SYS will open the DISPLAY device.
62 * This open call will end up in VIDEOPRT.SYS. That component will then
63 * take ownership of the display by calling HalAcquireDisplayOwnership.
64 * When the GUI app terminates (WIN32K.SYS will close the DISPLAY device),
65 * we want to give ownership of the display back to HAL. Using the
66 * standard exported HAL functions, that's a bit of a problem, because
67 * there is no function defined to do that. In NT, this is handled by
68 * HalDisplayString, but that solution isn't satisfactory in ReactOS,
69 * because HalDisplayString is (in some cases) also used to output debug
70 * messages. If we do it the NT way, the first debug message output while
71 * in graphics mode would switch the display back to text mode.
72 * So, instead, if HalDisplayString detects that HAL doesn't have ownership
73 * of the display, it doesn't do anything.
74 * To return ownership to HAL, a new function is exported,
75 * HalReleaseDisplayOwnership. This function is called by the DISPLAY
76 * device Close routine in VIDEOPRT.SYS. It is also called at the beginning
77 * of a bug check, so HalDisplayString is activated again.
78 * Now, while the display is in graphics mode (not owned by HAL), BLUE.SYS
79 * should also refrain from writing to the screen buffer. The text mode
80 * screen buffer might overlap the graphics mode screen buffer, so changing
81 * something in the text mode buffer might mess up the graphics screen. To
82 * allow BLUE.SYS to detect if HAL owns the display, another new function is
83 * exported, HalQueryDisplayOwnership. BLUE.SYS will call this function to
84 * check if it's allowed to touch the text mode buffer.
86 * In an ideal world, when HAL takes ownership of the display, it should set
87 * up the CRT using real-mode (actually V86 mode, but who cares) INT 0x10
88 * calls. Unfortunately, this will require HAL to setup a real-mode interrupt
89 * table etc. So, we chickened out of that by having the loader set up the
90 * display before switching to protected mode. If HAL is given back ownership
91 * after a GUI app terminates, the INT 0x10 calls are made by VIDEOPRT.SYS,
92 * since there is already support for them via the VideoPortInt10 routine.
95 #include <ddk/ntddk.h>
98 #define SCREEN_SYNCHRONIZATION
100 #define VGA_AC_INDEX 0x3c0
101 #define VGA_AC_READ 0x3c0
102 #define VGA_AC_WRITE 0x3c1
104 #define VGA_MISC_WRITE 0x3c2
106 #define VGA_SEQ_INDEX 0x3c4
107 #define VGA_SEQ_DATA 0x3c5
109 #define VGA_DAC_READ_INDEX 0x3c7
110 #define VGA_DAC_WRITE_INDEX 0x3c8
111 #define VGA_DAC_DATA 0x3c9
113 #define VGA_MISC_READ 0x3cc
115 #define VGA_GC_INDEX 0x3ce
116 #define VGA_GC_DATA 0x3cf
118 #define VGA_CRTC_INDEX 0x3d4
119 #define VGA_CRTC_DATA 0x3d5
121 #define VGA_INSTAT_READ 0x3da
123 #define VGA_SEQ_NUM_REGISTERS 5
124 #define VGA_CRTC_NUM_REGISTERS 25
125 #define VGA_GC_NUM_REGISTERS 9
126 #define VGA_AC_NUM_REGISTERS 21
128 #define CRTC_COLUMNS 0x01
129 #define CRTC_OVERFLOW 0x07
130 #define CRTC_ROWS 0x12
131 #define CRTC_SCANLINES 0x09
133 #define CRTC_CURHI 0x0e
134 #define CRTC_CURLO 0x0f
137 #define CHAR_ATTRIBUTE_BLACK 0x00 /* black on black */
138 #define CHAR_ATTRIBUTE 0x17 /* grey on blue */
141 /* VARIABLES ****************************************************************/
143 static ULONG CursorX
= 0; /* Cursor Position */
144 static ULONG CursorY
= 0;
145 static ULONG SizeX
= 80; /* Display size */
146 static ULONG SizeY
= 25;
148 static BOOLEAN DisplayInitialized
= FALSE
;
149 static BOOLEAN HalOwnsDisplay
= TRUE
;
151 static WORD
*VideoBuffer
= NULL
;
153 static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters
= NULL
;
155 static UCHAR TextPalette
[64][3] =
162 {42, 42, 42} /* 5 */,
164 {42, 42, 42} /* 7 */,
167 {0, 42, 21} /* 10 */,
168 {0, 42, 63} /* 11 */,
169 {42, 0, 21} /* 12 */,
170 {42, 0, 63} /* 13 */,
171 {42, 42, 21} /* 14 */,
172 {42, 42, 63} /* 15 */,
174 {0, 21, 42} /* 17 */,
176 {0, 63, 42} /* 19 */,
177 {42, 21, 0} /* 20 */,
178 {42, 21, 42} /* 21 */,
179 {42, 63, 0} /* 22 */,
180 {42, 63, 42} /* 23 */,
181 {0, 21, 21} /* 24 */,
182 {0, 21, 63} /* 25 */,
183 {0, 63, 21} /* 26 */,
184 {0, 63, 63} /* 27 */,
185 {42, 21, 21} /* 28 */,
186 {42, 21, 63} /* 29 */,
187 {42, 63, 21} /* 30 */,
188 {42, 63, 63} /* 31 */,
190 {21, 0, 42} /* 33 */,
191 {21, 42, 0} /* 34 */,
192 {21, 42, 42} /* 35 */,
194 {63, 0, 42} /* 37 */,
195 {63, 42, 0} /* 38 */,
196 {63, 42, 42} /* 39 */,
197 {21, 0, 21} /* 40 */,
198 {21, 0, 63} /* 41 */,
199 {21, 42, 21} /* 42 */,
200 {21, 42, 63} /* 43 */,
201 {63, 42, 0} /* 44 */,
202 {63, 0, 63} /* 45 */,
203 {63, 42, 21} /* 46 */,
204 {63, 42, 63} /* 47 */,
205 {21, 21, 0} /* 48 */,
206 {21, 21, 42} /* 49 */,
207 {21, 63, 0} /* 50 */,
208 {21, 63, 42} /* 51 */,
209 {63, 21, 0} /* 52 */,
210 {63, 21, 42} /* 53 */,
211 {63, 63, 0} /* 54 */,
212 {63, 63, 42} /* 55 */,
213 {21, 21, 21} /* 56 */,
214 {21, 21, 63} /* 57 */,
215 {21, 63, 21} /* 58 */,
216 {21, 63, 63} /* 59 */,
217 {63, 21, 21} /* 60 */,
218 {63, 21, 63} /* 61 */,
219 {63, 63, 21} /* 62 */,
220 {63, 63, 63} /* 63 */,
223 static UCHAR Text80x25Registers
[] =
228 0x03, 0x00, 0x03, 0x00, 0x02,
230 0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F,
231 0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x50,
232 0x9C, 0x0E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00,
238 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
239 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
240 0x0C, 0x00, 0x0F, 0x08, 0x00
243 static UCHAR Text80x50Registers
[] =
248 0x03, 0x00, 0x03, 0x00, 0x02,
250 0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F,
251 0x00, 0x47, 0x06, 0x07, 0x00, 0x00, 0x01, 0x40,
252 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3,
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00,
258 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
259 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
260 0x0C, 0x00, 0x0F, 0x08, 0x00,
264 /* STATIC FUNCTIONS *********************************************************/
267 HalClearDisplay (UCHAR CharAttribute
)
269 WORD
*ptr
= (WORD
*)VideoBuffer
;
272 for (i
= 0; i
< SizeX
* SizeY
; i
++, ptr
++)
273 *ptr
= ((CharAttribute
<< 8) + ' ');
281 HalScrollDisplay (VOID
)
286 ptr
= VideoBuffer
+ SizeX
;
287 RtlMoveMemory(VideoBuffer
,
289 SizeX
* (SizeY
- 1) * 2);
291 ptr
= VideoBuffer
+ (SizeX
* (SizeY
- 1));
292 for (i
= 0; i
< SizeX
; i
++, ptr
++)
294 *ptr
= (CHAR_ATTRIBUTE
<< 8) + ' ';
300 HalPutCharacter (CHAR Character
)
304 ptr
= VideoBuffer
+ ((CursorY
* SizeX
) + CursorX
);
305 *ptr
= (CHAR_ATTRIBUTE
<< 8) + Character
;
309 HalSetDisplayMode(PUCHAR Registers
)
314 /* Write MISC register. */
315 WRITE_PORT_UCHAR((PUCHAR
)VGA_MISC_WRITE
, *Registers
);
317 /* Write SEQUENCER registers. */
318 for (i
= 0; i
< VGA_SEQ_NUM_REGISTERS
; i
++)
320 WRITE_PORT_UCHAR((PUCHAR
)VGA_SEQ_INDEX
, i
);
321 WRITE_PORT_UCHAR((PUCHAR
)VGA_SEQ_DATA
, *Registers
);
324 /* Unlock CRTC registers. */
325 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, 0x03);
326 Port
= READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
);
327 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
, Port
| 0x80);
328 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, 0x11);
329 Port
= READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
);
330 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
, Port
& ~0x80);
331 /* Make sure they stay unlocked. */
332 Registers
[0x03] |= 0x80;
333 Registers
[0x11] &= ~0x80;
334 /* Write CRTC registers. */
335 for (i
= 0; i
< VGA_CRTC_NUM_REGISTERS
; i
++)
337 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, i
);
338 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
, *Registers
);
341 /* Write GC registers. */
342 for (i
= 0; i
< VGA_GC_NUM_REGISTERS
; i
++)
344 WRITE_PORT_UCHAR((PUCHAR
)VGA_GC_INDEX
, i
);
345 WRITE_PORT_UCHAR((PUCHAR
)VGA_GC_DATA
, *Registers
);
348 /* Write AC registers. */
349 for (i
= 0; i
< VGA_AC_NUM_REGISTERS
; i
++)
351 (VOID
)READ_PORT_UCHAR((PUCHAR
)VGA_INSTAT_READ
);
352 WRITE_PORT_UCHAR((PUCHAR
)VGA_AC_INDEX
, i
);
353 WRITE_PORT_UCHAR((PUCHAR
)VGA_AC_WRITE
, *Registers
);
357 for (i
= 0; i
< 64; i
++)
359 WRITE_PORT_UCHAR((PUCHAR
)0x03c8, i
);
360 WRITE_PORT_UCHAR((PUCHAR
)0x03c9, TextPalette
[i
][0]);
361 WRITE_PORT_UCHAR((PUCHAR
)0x03c9, TextPalette
[i
][1]);
362 WRITE_PORT_UCHAR((PUCHAR
)0x03c9, TextPalette
[i
][2]);
364 /* Lock 16-colour palette and unblank display. */
365 (VOID
)READ_PORT_UCHAR((PUCHAR
)VGA_INSTAT_READ
);
366 WRITE_PORT_UCHAR((PUCHAR
)VGA_AC_INDEX
, 0x20);
369 /* PRIVATE FUNCTIONS ********************************************************/
372 HalInitializeDisplay (PLOADER_PARAMETER_BLOCK LoaderBlock
)
374 * FUNCTION: Initalize the display
376 * InitParameters = Parameters setup by the boot loader
379 if (DisplayInitialized
== FALSE
)
384 VideoBuffer
= (WORD
*)(0xd0000000 + 0xb8000);
385 // VideoBuffer = HalMapPhysicalMemory (0xb8000, 2);
387 /* Set cursor position */
388 // CursorX = LoaderBlock->cursorx;
389 // CursorY = LoaderBlock->cursory;
393 /* read screen size from the crtc */
394 /* FIXME: screen size should be read from the boot parameters */
395 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_COLUMNS
);
396 SizeX
= READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
) + 1;
397 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_ROWS
);
398 SizeY
= READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
);
399 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_OVERFLOW
);
400 Data
= READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
);
401 SizeY
|= (((Data
& 0x02) << 7) | ((Data
& 0x40) << 3));
403 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_SCANLINES
);
404 ScanLines
= (READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
) & 0x1F) + 1;
405 SizeY
= SizeY
/ ScanLines
;
410 HalClearDisplay(CHAR_ATTRIBUTE_BLACK
);
412 DisplayInitialized
= TRUE
;
417 /* PUBLIC FUNCTIONS *********************************************************/
420 HalReleaseDisplayOwnership()
422 * FUNCTION: Release ownership of display back to HAL
425 if (HalResetDisplayParameters
== NULL
)
428 if (HalOwnsDisplay
== TRUE
)
431 if (!HalResetDisplayParameters(SizeX
, SizeY
))
433 if (SizeX
== 80 && SizeY
== 25)
435 HalSetDisplayMode(Text80x25Registers
);
441 HalSetDisplayMode(Text80x50Registers
);
444 HalOwnsDisplay
= TRUE
;
445 HalClearDisplay(CHAR_ATTRIBUTE
);
450 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
)
454 * ResetDisplayParameters = Pointer to a driver specific
458 HalOwnsDisplay
= FALSE
;
459 HalResetDisplayParameters
= ResetDisplayParameters
;
463 HalDisplayString(IN PCH String
)
465 * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there
466 * already and displays a string
468 * string = ASCII string to display
469 * NOTE: Use with care because there is no support for returning from BSOD
474 #ifdef SCREEN_SYNCHRONIZATION
477 static KSPIN_LOCK Lock
;
480 /* See comment at top of file */
481 if (! HalOwnsDisplay
)
490 KeAcquireSpinLockAtDpcLevel(&Lock
);
493 if (HalOwnsDisplay
== FALSE
)
495 HalReleaseDisplayOwnership();
499 #ifdef SCREEN_SYNCHRONIZATION
500 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_CURHI
);
501 offset
= READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
)<<8;
502 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_CURLO
);
503 offset
+= READ_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
);
505 CursorY
= offset
/ SizeX
;
506 CursorX
= offset
% SizeX
;
516 else if (*pch
!= '\r')
518 HalPutCharacter (*pch
);
521 if (CursorX
>= SizeX
)
528 if (CursorY
>= SizeY
)
537 #ifdef SCREEN_SYNCHRONIZATION
538 offset
= (CursorY
* SizeX
) + CursorX
;
540 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_CURLO
);
541 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
, offset
& 0xff);
542 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_INDEX
, CRTC_CURHI
);
543 WRITE_PORT_UCHAR((PUCHAR
)VGA_CRTC_DATA
, (offset
>> 8) & 0xff);
545 KeReleaseSpinLockFromDpcLevel(&Lock
);
550 HalQueryDisplayParameters(OUT PULONG DispSizeX
,
551 OUT PULONG DispSizeY
,
552 OUT PULONG CursorPosX
,
553 OUT PULONG CursorPosY
)
560 *CursorPosX
= CursorX
;
562 *CursorPosY
= CursorY
;
567 HalSetDisplayParameters(IN ULONG CursorPosX
,
570 CursorX
= (CursorPosX
< SizeX
) ? CursorPosX
: SizeX
- 1;
571 CursorY
= (CursorPosY
< SizeY
) ? CursorPosY
: SizeY
- 1;
575 HalQueryDisplayOwnership()
577 return ! HalOwnsDisplay
;