- Support for resetting the display mode on a bug check.
[reactos.git] / reactos / hal / halx86 / display.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: display.c,v 1.7 2003/08/24 11:58:16 dwelch Exp $
20 *
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)
26 * UPDATE HISTORY:
27 * Created 08/10/99
28 */
29
30 /* DISPLAY OWNERSHIP
31 *
32 * So, who owns the physical display and is allowed to write to it?
33 *
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).
46 *
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
56 * is present.
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.
85 *
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.
93 */
94
95 #include <ddk/ntddk.h>
96 #include <mps.h>
97
98 #define SCREEN_SYNCHRONIZATION
99
100 #define VGA_AC_INDEX 0x3c0
101 #define VGA_AC_READ 0x3c0
102 #define VGA_AC_WRITE 0x3c1
103
104 #define VGA_MISC_WRITE 0x3c2
105
106 #define VGA_SEQ_INDEX 0x3c4
107 #define VGA_SEQ_DATA 0x3c5
108
109 #define VGA_DAC_READ_INDEX 0x3c7
110 #define VGA_DAC_WRITE_INDEX 0x3c8
111 #define VGA_DAC_DATA 0x3c9
112
113 #define VGA_MISC_READ 0x3cc
114
115 #define VGA_GC_INDEX 0x3ce
116 #define VGA_GC_DATA 0x3cf
117
118 #define VGA_CRTC_INDEX 0x3d4
119 #define VGA_CRTC_DATA 0x3d5
120
121 #define VGA_INSTAT_READ 0x3da
122
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
127
128 #define CRTC_COLUMNS 0x01
129 #define CRTC_OVERFLOW 0x07
130 #define CRTC_ROWS 0x12
131 #define CRTC_SCANLINES 0x09
132
133 #define CRTC_CURHI 0x0e
134 #define CRTC_CURLO 0x0f
135
136
137 #define CHAR_ATTRIBUTE_BLACK 0x00 /* black on black */
138 #define CHAR_ATTRIBUTE 0x17 /* grey on blue */
139
140
141 /* VARIABLES ****************************************************************/
142
143 static ULONG CursorX = 0; /* Cursor Position */
144 static ULONG CursorY = 0;
145 static ULONG SizeX = 80; /* Display size */
146 static ULONG SizeY = 25;
147
148 static BOOLEAN DisplayInitialized = FALSE;
149 static BOOLEAN HalOwnsDisplay = TRUE;
150
151 static WORD *VideoBuffer = NULL;
152
153 static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters = NULL;
154
155 static UCHAR TextPalette[64][3] =
156 {
157 {0, 0, 0} /* 0 */,
158 {0, 0, 42} /* 1 */,
159 {0, 42, 0} /* 2 */,
160 {0, 42, 42} /* 3 */,
161 {42, 0, 0} /* 4 */,
162 {42, 42, 42} /* 5 */,
163 {42, 42, 0} /* 6 */,
164 {42, 42, 42} /* 7 */,
165 {0, 0, 21} /* 8 */,
166 {0, 0, 63} /* 9 */,
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 */,
173 {0, 21, 0} /* 16 */,
174 {0, 21, 42} /* 17 */,
175 {0, 63, 0} /* 18 */,
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 */,
189 {21, 0, 0} /* 32 */,
190 {21, 0, 42} /* 33 */,
191 {21, 42, 0} /* 34 */,
192 {21, 42, 42} /* 35 */,
193 {63, 0, 0} /* 36 */,
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 */,
221 };
222
223 static UCHAR Text80x25Registers[] =
224 {
225 /* MISC */
226 0x67,
227 /* SEQ */
228 0x03, 0x00, 0x03, 0x00, 0x02,
229 /* CRTC */
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,
233 0xFF,
234 /* GC */
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00,
236 0xFF,
237 /* AC */
238 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
239 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
240 0x0C, 0x00, 0x0F, 0x08, 0x00
241 };
242
243 static UCHAR Text80x50Registers[] =
244 {
245 /* MISC */
246 0x67,
247 /* SEQ */
248 0x03, 0x00, 0x03, 0x00, 0x02,
249 /* CRTC */
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,
253 0xFF,
254 /* GC */
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00,
256 0xFF,
257 /* AC */
258 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
259 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
260 0x0C, 0x00, 0x0F, 0x08, 0x00,
261 };
262
263
264 /* STATIC FUNCTIONS *********************************************************/
265
266 VOID
267 HalClearDisplay (UCHAR CharAttribute)
268 {
269 WORD *ptr = (WORD*)VideoBuffer;
270 ULONG i;
271
272 for (i = 0; i < SizeX * SizeY; i++, ptr++)
273 *ptr = ((CharAttribute << 8) + ' ');
274
275 CursorX = 0;
276 CursorY = 0;
277 }
278
279
280 VOID
281 HalScrollDisplay (VOID)
282 {
283 WORD *ptr;
284 int i;
285
286 ptr = VideoBuffer + SizeX;
287 RtlMoveMemory(VideoBuffer,
288 ptr,
289 SizeX * (SizeY - 1) * 2);
290
291 ptr = VideoBuffer + (SizeX * (SizeY - 1));
292 for (i = 0; i < SizeX; i++, ptr++)
293 {
294 *ptr = (CHAR_ATTRIBUTE << 8) + ' ';
295 }
296 }
297
298
299 static VOID
300 HalPutCharacter (CHAR Character)
301 {
302 WORD *ptr;
303
304 ptr = VideoBuffer + ((CursorY * SizeX) + CursorX);
305 *ptr = (CHAR_ATTRIBUTE << 8) + Character;
306 }
307
308 VOID STATIC
309 HalSetDisplayMode(PUCHAR Registers)
310 {
311 UCHAR Port;
312 ULONG i;
313
314 /* Write MISC register. */
315 WRITE_PORT_UCHAR((PUCHAR)VGA_MISC_WRITE, *Registers);
316 Registers++;
317 /* Write SEQUENCER registers. */
318 for (i = 0; i < VGA_SEQ_NUM_REGISTERS; i++)
319 {
320 WRITE_PORT_UCHAR((PUCHAR)VGA_SEQ_INDEX, i);
321 WRITE_PORT_UCHAR((PUCHAR)VGA_SEQ_DATA, *Registers);
322 Registers++;
323 }
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++)
336 {
337 WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_INDEX, i);
338 WRITE_PORT_UCHAR((PUCHAR)VGA_CRTC_DATA, *Registers);
339 Registers++;
340 }
341 /* Write GC registers. */
342 for (i = 0; i < VGA_GC_NUM_REGISTERS; i++)
343 {
344 WRITE_PORT_UCHAR((PUCHAR)VGA_GC_INDEX, i);
345 WRITE_PORT_UCHAR((PUCHAR)VGA_GC_DATA, *Registers);
346 Registers++;
347 }
348 /* Write AC registers. */
349 for (i = 0; i < VGA_AC_NUM_REGISTERS; i++)
350 {
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);
354 Registers++;
355 }
356 /* Reset palette. */
357 for (i = 0; i < 64; i++)
358 {
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]);
363 }
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);
367 }
368
369 /* PRIVATE FUNCTIONS ********************************************************/
370
371 VOID
372 HalInitializeDisplay (PLOADER_PARAMETER_BLOCK LoaderBlock)
373 /*
374 * FUNCTION: Initalize the display
375 * ARGUMENTS:
376 * InitParameters = Parameters setup by the boot loader
377 */
378 {
379 if (DisplayInitialized == FALSE)
380 {
381 ULONG ScanLines;
382 ULONG Data;
383
384 VideoBuffer = (WORD *)(0xd0000000 + 0xb8000);
385 // VideoBuffer = HalMapPhysicalMemory (0xb8000, 2);
386
387 /* Set cursor position */
388 // CursorX = LoaderBlock->cursorx;
389 // CursorY = LoaderBlock->cursory;
390 CursorX = 0;
391 CursorY = 0;
392
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));
402 SizeY++;
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;
406
407 #ifdef BOCHS_30ROWS
408 SizeY=30;
409 #endif
410 HalClearDisplay(CHAR_ATTRIBUTE_BLACK);
411
412 DisplayInitialized = TRUE;
413 }
414 }
415
416
417 /* PUBLIC FUNCTIONS *********************************************************/
418
419 VOID STDCALL
420 HalReleaseDisplayOwnership()
421 /*
422 * FUNCTION: Release ownership of display back to HAL
423 */
424 {
425 if (HalResetDisplayParameters == NULL)
426 return;
427
428 if (HalOwnsDisplay == TRUE)
429 return;
430
431 if (!HalResetDisplayParameters(SizeX, SizeY))
432 {
433 if (SizeX == 80 && SizeY == 25)
434 {
435 HalSetDisplayMode(Text80x25Registers);
436 }
437 else
438 {
439 SizeX = 80;
440 SizeY = 50;
441 HalSetDisplayMode(Text80x50Registers);
442 }
443 }
444 HalOwnsDisplay = TRUE;
445 HalClearDisplay(CHAR_ATTRIBUTE);
446 }
447
448
449 VOID STDCALL
450 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters)
451 /*
452 * FUNCTION:
453 * ARGUMENTS:
454 * ResetDisplayParameters = Pointer to a driver specific
455 * reset routine.
456 */
457 {
458 HalOwnsDisplay = FALSE;
459 HalResetDisplayParameters = ResetDisplayParameters;
460 }
461
462 VOID STDCALL
463 HalDisplayString(IN PCH String)
464 /*
465 * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there
466 * already and displays a string
467 * ARGUMENT:
468 * string = ASCII string to display
469 * NOTE: Use with care because there is no support for returning from BSOD
470 * mode
471 */
472 {
473 PCH pch;
474 #ifdef SCREEN_SYNCHRONIZATION
475 int offset;
476 #endif
477 static KSPIN_LOCK Lock;
478 ULONG Flags;
479
480 /* See comment at top of file */
481 if (! HalOwnsDisplay)
482 {
483 return;
484 }
485
486 pch = String;
487
488 pushfl(Flags);
489 __asm__ ("cli\n\t");
490 KeAcquireSpinLockAtDpcLevel(&Lock);
491
492 #if 0
493 if (HalOwnsDisplay == FALSE)
494 {
495 HalReleaseDisplayOwnership();
496 }
497 #endif
498
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);
504
505 CursorY = offset / SizeX;
506 CursorX = offset % SizeX;
507 #endif
508
509 while (*pch != 0)
510 {
511 if (*pch == '\n')
512 {
513 CursorY++;
514 CursorX = 0;
515 }
516 else if (*pch != '\r')
517 {
518 HalPutCharacter (*pch);
519 CursorX++;
520
521 if (CursorX >= SizeX)
522 {
523 CursorY++;
524 CursorX = 0;
525 }
526 }
527
528 if (CursorY >= SizeY)
529 {
530 HalScrollDisplay ();
531 CursorY = SizeY - 1;
532 }
533
534 pch++;
535 }
536
537 #ifdef SCREEN_SYNCHRONIZATION
538 offset = (CursorY * SizeX) + CursorX;
539
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);
544 #endif
545 KeReleaseSpinLockFromDpcLevel(&Lock);
546 popfl(Flags);
547 }
548
549 VOID STDCALL
550 HalQueryDisplayParameters(OUT PULONG DispSizeX,
551 OUT PULONG DispSizeY,
552 OUT PULONG CursorPosX,
553 OUT PULONG CursorPosY)
554 {
555 if (DispSizeX)
556 *DispSizeX = SizeX;
557 if (DispSizeY)
558 *DispSizeY = SizeY;
559 if (CursorPosX)
560 *CursorPosX = CursorX;
561 if (CursorPosY)
562 *CursorPosY = CursorY;
563 }
564
565
566 VOID STDCALL
567 HalSetDisplayParameters(IN ULONG CursorPosX,
568 IN ULONG CursorPosY)
569 {
570 CursorX = (CursorPosX < SizeX) ? CursorPosX : SizeX - 1;
571 CursorY = (CursorPosY < SizeY) ? CursorPosY : SizeY - 1;
572 }
573
574 BOOLEAN STDCALL
575 HalQueryDisplayOwnership()
576 {
577 return ! HalOwnsDisplay;
578 }
579
580 /* EOF */