Added freeldr and hal from PPC branch, along with needed headers and
[reactos.git] / reactos / hal / halppc / generic / display.c
diff --git a/reactos/hal/halppc/generic/display.c b/reactos/hal/halppc/generic/display.c
new file mode 100644 (file)
index 0000000..4e0d8ed
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ *  ReactOS kernel
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: display.c 23907 2006-09-04 05:52:23Z arty $
+ *
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/hal/x86/display.c
+ * PURPOSE:         Blue screen display
+ * PROGRAMMER:      Eric Kohl (ekohl@rz-online.de)
+ * UPDATE HISTORY:
+ *                  Created 08/10/99
+ */
+
+/*
+ * Portions of this code are from the XFree86 Project and available from the
+ * following license:
+ *
+ * Copyright (C) 1994-2003 The XFree86 Project, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+ * NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the XFree86 Project shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from the
+ * XFree86 Project.
+*/  
+
+/* DISPLAY OWNERSHIP
+ *
+ * So, who owns the physical display and is allowed to write to it?
+ *
+ * In MS NT, upon boot HAL owns the display. Somewhere in the boot
+ * sequence (haven't figured out exactly where or by who), some
+ * component calls HalAcquireDisplayOwnership. From that moment on,
+ * the display is owned by that component and is switched to graphics
+ * mode. The display is not supposed to return to text mode, except
+ * in case of a bug check. The bug check will call HalDisplayString
+ * to output a string to the text screen. HAL will notice that it
+ * currently doesn't own the display and will re-take ownership, by
+ * calling the callback function passed to HalAcquireDisplayOwnership.
+ * After the bugcheck, execution is halted. So, under NT, the only
+ * possible sequence of display modes is text mode -> graphics mode ->
+ * text mode (the latter hopefully happening very infrequently).
+ *
+ * Things are a little bit different in the current state of ReactOS.
+ * We want to have a functional interactive text mode. We should be
+ * able to switch from text mode to graphics mode when a GUI app is
+ * started and switch back to text mode when it's finished. Then, when
+ * another GUI app is started, another switch to and from graphics mode
+ * is possible. Also, when the system bugchecks in graphics mode we want
+ * to switch back to text mode to show the registers and stack trace.
+ * Last but not least, HalDisplayString is used a lot more in ReactOS,
+ * e.g. to print debug messages when the /DEBUGPORT=SCREEN boot option
+ * is present.
+ * 3 Components are involved in Reactos: HAL, BLUE.SYS and VIDEOPRT.SYS.
+ * As in NT, on boot HAL owns the display. When entering the text mode
+ * command interpreter, BLUE.SYS kicks in. It will write directly to the
+ * screen, more or less behind HALs back.
+ * When a GUI app is started, WIN32K.SYS will open the DISPLAY device.
+ * This open call will end up in VIDEOPRT.SYS. That component will then
+ * take ownership of the display by calling HalAcquireDisplayOwnership.
+ * When the GUI app terminates (WIN32K.SYS will close the DISPLAY device),
+ * we want to give ownership of the display back to HAL. Using the
+ * standard exported HAL functions, that's a bit of a problem, because
+ * there is no function defined to do that. In NT, this is handled by
+ * HalDisplayString, but that solution isn't satisfactory in ReactOS,
+ * because HalDisplayString is (in some cases) also used to output debug
+ * messages. If we do it the NT way, the first debug message output while
+ * in graphics mode would switch the display back to text mode.
+ * So, instead, if HalDisplayString detects that HAL doesn't have ownership
+ * of the display, it doesn't do anything.
+ * To return ownership to HAL, a new function is exported,
+ * HalReleaseDisplayOwnership. This function is called by the DISPLAY
+ * device Close routine in VIDEOPRT.SYS. It is also called at the beginning
+ * of a bug check, so HalDisplayString is activated again.
+ * Now, while the display is in graphics mode (not owned by HAL), BLUE.SYS
+ * should also refrain from writing to the screen buffer. The text mode
+ * screen buffer might overlap the graphics mode screen buffer, so changing
+ * something in the text mode buffer might mess up the graphics screen. To
+ * allow BLUE.SYS to detect if HAL owns the display, another new function is
+ * exported, HalQueryDisplayOwnership. BLUE.SYS will call this function to
+ * check if it's allowed to touch the text mode buffer.
+ *
+ * In an ideal world, when HAL takes ownership of the display, it should set
+ * up the CRT using real-mode (actually V86 mode, but who cares) INT 0x10
+ * calls. Unfortunately, this will require HAL to setup a real-mode interrupt
+ * table etc. So, we chickened out of that by having the loader set up the
+ * display before switching to protected mode. If HAL is given back ownership
+ * after a GUI app terminates, the INT 0x10 calls are made by VIDEOPRT.SYS,
+ * since there is already support for them via the VideoPortInt10 routine.
+ */
+
+#include <hal.h>
+#include <rosldr.h>
+#include <ppcboot.h>
+#include <ppcdebug.h>
+
+#define NDEBUG
+#include <debug.h>
+
+boot_infos_t PpcEarlybootInfo;
+
+#define SCREEN_SYNCHRONIZATION
+
+/* VARIABLES ****************************************************************/
+
+static ULONG CursorX = 0;      /* Cursor Position */
+static ULONG CursorY = 0;
+static ULONG SizeX = 80;       /* Display size */
+static ULONG SizeY = 25;
+
+static BOOLEAN DisplayInitialized = FALSE;
+static BOOLEAN HalOwnsDisplay = TRUE;
+static ULONG GraphVideoBuffer = 0;
+static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters = NULL;
+
+extern UCHAR XboxFont8x16[];
+extern void SetPhys( ULONG Addr, ULONG Data );
+extern ULONG GetPhys( ULONG Addr );
+extern void SetPhysByte( ULONG Addr, ULONG Data );
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID FASTCALL
+HalClearDisplay (UCHAR CharAttribute)
+{
+   ULONG i;
+   ULONG deviceSize = 
+       PpcEarlybootInfo.dispDeviceRowBytes *
+       PpcEarlybootInfo.dispDeviceRect[3];
+   for(i = 0; i < deviceSize; i += sizeof(int) ) 
+       SetPhys(GraphVideoBuffer + i, CharAttribute);
+
+   CursorX = 0;
+   CursorY = 0;
+}
+
+
+/* STATIC FUNCTIONS *********************************************************/
+
+VOID STATIC
+HalScrollDisplay (VOID)
+{
+    ULONG i, deviceSize = 
+       PpcEarlybootInfo.dispDeviceRowBytes *
+       PpcEarlybootInfo.dispDeviceRect[3];
+    ULONG Dest = (ULONG)GraphVideoBuffer, 
+       Src = (ULONG)(GraphVideoBuffer + (16 * PpcEarlybootInfo.dispDeviceRowBytes));
+    ULONG End  = (ULONG)
+       GraphVideoBuffer + 
+       (PpcEarlybootInfo.dispDeviceRowBytes *
+        (PpcEarlybootInfo.dispDeviceRect[3]-16));
+    
+    while( Src < End ) 
+    {
+       SetPhys((ULONG)Dest, GetPhys(Src));
+       Src += 4; Dest += 4;
+    }
+
+    /* Clear the bottom row */
+    for(i = End; i < deviceSize; i += sizeof(int) ) 
+       SetPhys(GraphVideoBuffer + i, 1);
+}
+
+VOID STATIC FASTCALL
+HalPutCharacter (CHAR Character)
+{
+    WRITE_PORT_UCHAR((PVOID)0x3f8, Character);
+#if 0
+    int i,j,k;
+    ULONG Dest =
+       (GraphVideoBuffer + 
+        (16 * PpcEarlybootInfo.dispDeviceRowBytes * CursorY) + 
+        (8 * (PpcEarlybootInfo.dispDeviceDepth / 8) * CursorX)), RowDest;
+    UCHAR ByteToPlace;
+
+    for( i = 0; i < 16; i++ ) {
+       RowDest = Dest;
+       for( j = 0; j < 8; j++ ) {
+           ByteToPlace = ((128 >> j) & (XboxFont8x16[(16 * Character) + i])) ? 0xff : 1;
+           for( k = 0; k < PpcEarlybootInfo.dispDeviceDepth / 8; k++, RowDest++ ) {
+               SetPhysByte(RowDest, ByteToPlace);
+           }
+       }
+       Dest += PpcEarlybootInfo.dispDeviceRowBytes;
+    }
+#endif
+}
+
+/* PRIVATE FUNCTIONS ********************************************************/
+
+VOID FASTCALL
+HalInitializeDisplay (PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
+/*
+ * FUNCTION: Initalize the display
+ * ARGUMENTS:
+ *         InitParameters = Parameters setup by the boot loader
+ */
+{
+    if (! DisplayInitialized)
+    {
+      boot_infos_t *XBootInfo = (boot_infos_t *)LoaderBlock->ArchExtra;
+      GraphVideoBuffer = (ULONG)XBootInfo->dispDeviceBase;
+      memcpy(&PpcEarlybootInfo, XBootInfo, sizeof(*XBootInfo));
+
+      /* Set cursor position */
+      CursorX = 0;
+      CursorY = 0;
+
+      SizeX = XBootInfo->dispDeviceRowBytes / XBootInfo->dispDeviceDepth;
+      SizeY = XBootInfo->dispDeviceRect[3] / 16;
+
+      HalClearDisplay(1);
+
+      DisplayInitialized = TRUE;
+    }
+}
+
+
+/* PUBLIC FUNCTIONS *********************************************************/
+
+VOID STDCALL
+HalReleaseDisplayOwnership(VOID)
+/*
+ * FUNCTION: Release ownership of display back to HAL
+ */
+{
+  if (HalResetDisplayParameters == NULL)
+    return;
+
+  if (HalOwnsDisplay == TRUE)
+    return;
+
+  HalOwnsDisplay = TRUE;
+  HalClearDisplay(0);
+}
+
+
+VOID STDCALL
+HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters)
+/*
+ * FUNCTION: 
+ * ARGUMENTS:
+ *         ResetDisplayParameters = Pointer to a driver specific
+ *         reset routine.
+ */
+{
+  HalOwnsDisplay = FALSE;
+  HalResetDisplayParameters = ResetDisplayParameters;
+}
+
+VOID STDCALL
+HalDisplayString(IN PCH String)
+/*
+ * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there
+ * already and displays a string
+ * ARGUMENT:
+ *        string = ASCII string to display
+ * NOTE: Use with care because there is no support for returning from BSOD
+ * mode
+ */
+{
+  PCH pch;
+  //static KSPIN_LOCK Lock;
+  KIRQL OldIrql;
+  BOOLEAN InterruptsEnabled = __readmsr();
+
+  /* See comment at top of file */
+  if (! HalOwnsDisplay || ! DisplayInitialized)
+    {
+      return;
+    }
+
+  pch = String;
+
+  KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+  //KiAcquireSpinLock(&Lock);
+
+  _disable();
+  
+  while (*pch != 0)
+    {
+      if (*pch == '\n')
+       {
+         CursorY++;
+         CursorX = 0;
+       }
+      else if (*pch == '\b')
+       {
+         if (CursorX > 0)
+           {
+             CursorX--;
+           }
+       }
+      else if (*pch != '\r')
+       {
+         HalPutCharacter (*pch);
+         CursorX++;
+         
+         if (CursorX >= SizeX)
+           {
+             CursorY++;
+             CursorX = 0;
+           }
+       }
+  
+      if (CursorY >= SizeY)
+       {
+         HalScrollDisplay ();
+         CursorY = SizeY - 1;
+       }
+
+      pch++;
+    }
+
+  __writemsr(InterruptsEnabled);
+
+  //KiReleaseSpinLock(&Lock);
+  KeLowerIrql(OldIrql);
+}
+
+VOID STDCALL
+HalQueryDisplayParameters(OUT PULONG DispSizeX,
+                         OUT PULONG DispSizeY,
+                         OUT PULONG CursorPosX,
+                         OUT PULONG CursorPosY)
+{
+  if (DispSizeX)
+    *DispSizeX = SizeX;
+  if (DispSizeY)
+    *DispSizeY = SizeY;
+  if (CursorPosX)
+    *CursorPosX = CursorX;
+  if (CursorPosY)
+    *CursorPosY = CursorY;
+}
+
+
+VOID STDCALL
+HalSetDisplayParameters(IN ULONG CursorPosX,
+                       IN ULONG CursorPosY)
+{
+  CursorX = (CursorPosX < SizeX) ? CursorPosX : SizeX - 1;
+  CursorY = (CursorPosY < SizeY) ? CursorPosY : SizeY - 1;
+}
+
+
+BOOLEAN STDCALL
+HalQueryDisplayOwnership(VOID)
+{
+  return !HalOwnsDisplay;
+}
+
+/* EOF */