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.6 2003/08/11 18:50:12 chorns 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_BLACK 0x00 /* black on black */
114 #define CHAR_ATTRIBUTE 0x17 /* grey on blue */
117 /* VARIABLES ****************************************************************/
119 static ULONG CursorX
= 0; /* Cursor Position */
120 static ULONG CursorY
= 0;
121 static ULONG SizeX
= 80; /* Display size */
122 static ULONG SizeY
= 25;
124 static BOOLEAN DisplayInitialized
= FALSE
;
125 static BOOLEAN HalOwnsDisplay
= TRUE
;
127 static WORD
*VideoBuffer
= NULL
;
129 static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters
= NULL
;
132 /* STATIC FUNCTIONS *********************************************************/
135 HalClearDisplay (UCHAR CharAttribute
)
137 WORD
*ptr
= (WORD
*)VideoBuffer
;
140 for (i
= 0; i
< SizeX
* SizeY
; i
++, ptr
++)
141 *ptr
= ((CharAttribute
<< 8) + ' ');
149 HalScrollDisplay (VOID
)
154 ptr
= VideoBuffer
+ SizeX
;
155 RtlMoveMemory(VideoBuffer
,
157 SizeX
* (SizeY
- 1) * 2);
159 ptr
= VideoBuffer
+ (SizeX
* (SizeY
- 1));
160 for (i
= 0; i
< SizeX
; i
++, ptr
++)
162 *ptr
= (CHAR_ATTRIBUTE
<< 8) + ' ';
168 HalPutCharacter (CHAR Character
)
172 ptr
= VideoBuffer
+ ((CursorY
* SizeX
) + CursorX
);
173 *ptr
= (CHAR_ATTRIBUTE
<< 8) + Character
;
177 /* PRIVATE FUNCTIONS ********************************************************/
180 HalInitializeDisplay (PLOADER_PARAMETER_BLOCK LoaderBlock
)
182 * FUNCTION: Initalize the display
184 * InitParameters = Parameters setup by the boot loader
187 if (DisplayInitialized
== FALSE
)
192 VideoBuffer
= (WORD
*)(0xd0000000 + 0xb8000);
193 // VideoBuffer = HalMapPhysicalMemory (0xb8000, 2);
195 /* Set cursor position */
196 // CursorX = LoaderBlock->cursorx;
197 // CursorY = LoaderBlock->cursory;
201 /* read screen size from the crtc */
202 /* FIXME: screen size should be read from the boot parameters */
203 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_COLUMNS
);
204 SizeX
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
) + 1;
205 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_ROWS
);
206 SizeY
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
);
207 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_OVERFLOW
);
208 Data
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
);
209 SizeY
|= (((Data
& 0x02) << 7) | ((Data
& 0x40) << 3));
211 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_SCANLINES
);
212 ScanLines
= (READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
) & 0x1F) + 1;
213 SizeY
= SizeY
/ ScanLines
;
218 HalClearDisplay(CHAR_ATTRIBUTE_BLACK
);
220 DisplayInitialized
= TRUE
;
225 /* PUBLIC FUNCTIONS *********************************************************/
228 HalReleaseDisplayOwnership()
230 * FUNCTION: Release ownership of display back to HAL
233 if (HalResetDisplayParameters
== NULL
)
236 if (HalOwnsDisplay
== TRUE
)
239 if (HalResetDisplayParameters(SizeX
, SizeY
) == TRUE
)
241 HalOwnsDisplay
= TRUE
;
242 HalClearDisplay(CHAR_ATTRIBUTE
);
248 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
)
252 * ResetDisplayParameters = Pointer to a driver specific
256 HalOwnsDisplay
= FALSE
;
257 HalResetDisplayParameters
= ResetDisplayParameters
;
261 HalDisplayString(IN PCH String
)
263 * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there
264 * already and displays a string
266 * string = ASCII string to display
267 * NOTE: Use with care because there is no support for returning from BSOD
272 #ifdef SCREEN_SYNCHRONIZATION
275 static KSPIN_LOCK Lock
;
278 /* See comment at top of file */
279 if (! HalOwnsDisplay
)
288 KeAcquireSpinLockAtDpcLevel(&Lock
);
291 if (HalOwnsDisplay
== FALSE
)
293 HalReleaseDisplayOwnership();
297 #ifdef SCREEN_SYNCHRONIZATION
298 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURHI
);
299 offset
= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
)<<8;
300 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURLO
);
301 offset
+= READ_PORT_UCHAR((PUCHAR
)CRTC_DATA
);
303 CursorY
= offset
/ SizeX
;
304 CursorX
= offset
% SizeX
;
314 else if (*pch
!= '\r')
316 HalPutCharacter (*pch
);
319 if (CursorX
>= SizeX
)
326 if (CursorY
>= SizeY
)
335 #ifdef SCREEN_SYNCHRONIZATION
336 offset
= (CursorY
* SizeX
) + CursorX
;
338 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURLO
);
339 WRITE_PORT_UCHAR((PUCHAR
)CRTC_DATA
, offset
& 0xff);
340 WRITE_PORT_UCHAR((PUCHAR
)CRTC_COMMAND
, CRTC_CURHI
);
341 WRITE_PORT_UCHAR((PUCHAR
)CRTC_DATA
, (offset
>> 8) & 0xff);
343 KeReleaseSpinLockFromDpcLevel(&Lock
);
348 HalQueryDisplayParameters(OUT PULONG DispSizeX
,
349 OUT PULONG DispSizeY
,
350 OUT PULONG CursorPosX
,
351 OUT PULONG CursorPosY
)
358 *CursorPosX
= CursorX
;
360 *CursorPosY
= CursorY
;
365 HalSetDisplayParameters(IN ULONG CursorPosX
,
368 CursorX
= (CursorPosX
< SizeX
) ? CursorPosX
: SizeX
- 1;
369 CursorY
= (CursorPosY
< SizeY
) ? CursorPosY
: SizeY
- 1;
373 HalQueryDisplayOwnership()
375 return ! HalOwnsDisplay
;