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.5 2003/06/21 14:25:30 gvg 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
101 #define CRTC_COMMAND 0x3d4
102 #define CRTC_DATA 0x3d5
104 #define CRTC_COLUMNS 0x01
105 #define CRTC_OVERFLOW 0x07
106 #define CRTC_ROWS 0x12
107 #define CRTC_SCANLINES 0x09
109 #define CRTC_CURHI 0x0e
110 #define CRTC_CURLO 0x0f
113 #define CHAR_ATTRIBUTE 0x17 /* grey on blue */
116 /* VARIABLES ****************************************************************/
118 static ULONG CursorX
= 0; /* Cursor Position */
119 static ULONG CursorY
= 0;
120 static ULONG SizeX
= 80; /* Display size */
121 static ULONG SizeY
= 25;
123 static BOOLEAN DisplayInitialized
= FALSE
;
124 static BOOLEAN HalOwnsDisplay
= TRUE
;
126 static WORD
*VideoBuffer
= NULL
;
128 static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters
= NULL
;
131 /* STATIC FUNCTIONS *********************************************************/
134 HalClearDisplay (VOID
)
136 WORD
*ptr
= (WORD
*)VideoBuffer
;
139 for (i
= 0; i
< SizeX
* SizeY
; i
++, ptr
++)
140 *ptr
= ((CHAR_ATTRIBUTE
<< 8) + ' ');
148 HalScrollDisplay (VOID
)
153 ptr
= VideoBuffer
+ SizeX
;
154 RtlMoveMemory(VideoBuffer
,
156 SizeX
* (SizeY
- 1) * 2);
158 ptr
= VideoBuffer
+ (SizeX
* (SizeY
- 1));
159 for (i
= 0; i
< SizeX
; i
++, ptr
++)
161 *ptr
= (CHAR_ATTRIBUTE
<< 8) + ' ';
167 HalPutCharacter (CHAR Character
)
171 ptr
= VideoBuffer
+ ((CursorY
* SizeX
) + CursorX
);
172 *ptr
= (CHAR_ATTRIBUTE
<< 8) + Character
;
176 /* PRIVATE FUNCTIONS ********************************************************/
179 HalInitializeDisplay (PLOADER_PARAMETER_BLOCK LoaderBlock
)
181 * FUNCTION: Initalize the display
183 * InitParameters = Parameters setup by the boot loader
186 if (DisplayInitialized
== FALSE
)
191 VideoBuffer
= (WORD
*)(0xd0000000 + 0xb8000);
192 // VideoBuffer = HalMapPhysicalMemory (0xb8000, 2);
194 /* Set cursor position */
195 // CursorX = LoaderBlock->cursorx;
196 // CursorY = LoaderBlock->cursory;
200 /* read screen size from the crtc */
201 /* FIXME: screen size should be read from the boot parameters */
202 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_COLUMNS
);
203 SizeX
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
) + 1;
204 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_ROWS
);
205 SizeY
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
);
206 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_OVERFLOW
);
207 Data
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
);
208 SizeY
|= (((Data
& 0x02) << 7) | ((Data
& 0x40) << 3));
210 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_SCANLINES
);
211 ScanLines
= (READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
) & 0x1F) + 1;
212 SizeY
= SizeY
/ ScanLines
;
219 DisplayInitialized
= TRUE
;
224 /* PUBLIC FUNCTIONS *********************************************************/
227 HalReleaseDisplayOwnership()
229 * FUNCTION: Release ownership of display back to HAL
232 if (HalResetDisplayParameters
== NULL
)
235 if (HalOwnsDisplay
== TRUE
)
238 if (HalResetDisplayParameters(SizeX
, SizeY
) == TRUE
)
240 HalOwnsDisplay
= TRUE
;
247 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
)
251 * ResetDisplayParameters = Pointer to a driver specific
255 HalOwnsDisplay
= FALSE
;
256 HalResetDisplayParameters
= ResetDisplayParameters
;
260 HalDisplayString(IN PCH String
)
262 * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there
263 * already and displays a string
265 * string = ASCII string to display
266 * NOTE: Use with care because there is no support for returning from BSOD
271 #ifdef SCREEN_SYNCHRONIZATION
274 static KSPIN_LOCK Lock
;
277 /* See comment at top of file */
278 if (! HalOwnsDisplay
)
287 KeAcquireSpinLockAtDpcLevel(&Lock
);
290 if (HalOwnsDisplay
== FALSE
)
292 HalReleaseDisplayOwnership();
296 #ifdef SCREEN_SYNCHRONIZATION
297 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURHI
);
298 offset
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
)<<8;
299 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURLO
);
300 offset
+= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
);
302 CursorY
= offset
/ SizeX
;
303 CursorX
= offset
% SizeX
;
313 else if (*pch
!= '\r')
315 HalPutCharacter (*pch
);
318 if (CursorX
>= SizeX
)
325 if (CursorY
>= SizeY
)
334 #ifdef SCREEN_SYNCHRONIZATION
335 offset
= (CursorY
* SizeX
) + CursorX
;
337 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURLO
);
338 WRITE_PORT_UCHAR((PUCHAR
)CRTC_DATA
, offset
& 0xff);
339 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURHI
);
340 WRITE_PORT_UCHAR((PUCHAR
)CRTC_DATA
, (offset
>> 8) & 0xff);
342 KeReleaseSpinLockFromDpcLevel(&Lock
);
347 HalQueryDisplayParameters(OUT PULONG DispSizeX
,
348 OUT PULONG DispSizeY
,
349 OUT PULONG CursorPosX
,
350 OUT PULONG CursorPosY
)
357 *CursorPosX
= CursorX
;
359 *CursorPosY
= CursorY
;
364 HalSetDisplayParameters(IN ULONG CursorPosX
,
367 CursorX
= (CursorPosX
< SizeX
) ? CursorPosX
: SizeX
- 1;
368 CursorY
= (CursorPosY
< SizeY
) ? CursorPosY
: SizeY
- 1;
372 HalQueryDisplayOwnership()
374 return ! HalOwnsDisplay
;