[FREELDR][XBOXVMP] Check only low 28 bits for framebuffer address (#2249)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / xboxvideo.c
index 866db66..b1fd251 100644 (file)
  */
 
 #include <freeldr.h>
+#include <debug.h>
 
-static PVOID FrameBuffer;
+DBG_DEFAULT_CHANNEL(UI);
+
+PVOID FrameBuffer;
+ULONG FrameBufferSize;
 static ULONG ScreenWidth;
 static ULONG ScreenHeight;
 static ULONG BytesPerPixel;
 static ULONG Delta;
+extern multiboot_info_t * MultibootInfoPtr;
 
 #define CHAR_WIDTH  8
 #define CHAR_HEIGHT 16
@@ -36,8 +41,6 @@ static ULONG Delta;
 
 #define MAKE_COLOR(Red, Green, Blue) (0xff000000 | (((Red) & 0xff) << 16) | (((Green) & 0xff) << 8) | ((Blue) & 0xff))
 
-BOOLEAN I2CTransmitByteGetReturn(UCHAR bPicAddressI2cFormat, UCHAR bDataToWrite, ULONG *Return);
-
 static VOID
 XboxVideoOutputChar(UCHAR Char, unsigned X, unsigned Y, ULONG FgColor, ULONG BgColor)
 {
@@ -118,45 +121,94 @@ XboxVideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y)
   XboxVideoOutputChar(Ch, X, Y, FgColor, BgColor);
 }
 
-VOID
-XboxVideoInit(VOID)
+UCHAR
+NvGetCrtc(UCHAR Index)
 {
-  ULONG AvMode;
+    *((PUCHAR) NV2A_CRTC_REGISTER_INDEX) = Index;
+    return *((PUCHAR) NV2A_CRTC_REGISTER_VALUE);
+}
 
-  FrameBuffer = (PVOID)((ULONG) XboxMemReserveMemory(FB_SIZE_MB) | 0xf0000000);
+ULONG
+XboxGetFramebufferSize(PVOID Offset)
+{
+    memory_map_t * MemoryMap;
+    INT Count, i;
 
-  if (I2CTransmitByteGetReturn(0x10, 0x04, &AvMode))
+    if (!MultibootInfoPtr)
     {
-      if (1 == AvMode) /* HDTV */
-        {
-          ScreenWidth = 720;
-        }
-      else
-        {
-          /* FIXME Other possible values of AvMode:
-           * 0 - AV_SCART_RGB
-           * 2 - AV_VGA_SOG
-           * 4 - AV_SVIDEO
-           * 6 - AV_COMPOSITE
-           * 7 - AV_VGA
-           * other AV_COMPOSITE
-           */
-          ScreenWidth = 640;
-        }
+        return 0;
     }
-  else
+
+    if (!(MultibootInfoPtr->flags & MB_INFO_FLAG_MEMORY_MAP))
     {
-      ScreenWidth = 640;
+        return 0;
     }
 
-  ScreenHeight = 480;
-  BytesPerPixel = 4;
+    MemoryMap = (memory_map_t *)MultibootInfoPtr->mmap_addr;
+
+    if (!MemoryMap ||
+        MultibootInfoPtr->mmap_length == 0 ||
+        MultibootInfoPtr->mmap_length % sizeof(memory_map_t) != 0)
+    {
+        return 0;
+    }
+
+    Count = MultibootInfoPtr->mmap_length / sizeof(memory_map_t);
+    for (i = 0; i < Count; i++, MemoryMap++)
+    {
+        TRACE("i = %d, base_addr_low = 0x%p, MemoryMap->length_low = 0x%p\n", i, MemoryMap->base_addr_low, MemoryMap->length_low);
+
+        /* Framebuffer address offset value is coming from the GPU within
+         * memory mapped I/O address space, so we're comparing only low
+         * 28 bits of the address within actual RAM address space */
+        if (MemoryMap->base_addr_low == ((ULONG)Offset & 0x0FFFFFFF) && MemoryMap->base_addr_high == 0)
+        {
+            TRACE("Video memory found\n");
+            return MemoryMap->length_low;
+        }
+    }
+    ERR("Video memory not found!\n");
+    return 0;
+}
+
+VOID
+XboxVideoInit(VOID)
+{
+  /* Reuse framebuffer that was set up by firmware */
+  FrameBuffer = (PVOID)*((PULONG) NV2A_CRTC_FRAMEBUFFER_START);
+  /* Verify that framebuffer address is page-aligned */
+  ASSERT((ULONG_PTR)FrameBuffer % PAGE_SIZE == 0);
+
+  /* Obtain framebuffer memory size from multiboot memory map */
+  if ((FrameBufferSize = XboxGetFramebufferSize(FrameBuffer)) == 0)
+  {
+    /* Fallback to Cromwell standard which reserves high 4 MB of RAM */
+    FrameBufferSize = 4 * 1024 * 1024;
+    WARN("Could not detect framebuffer memory size, fallback to 4 MB\n");
+  }
+
+  ScreenWidth = *((PULONG) NV2A_RAMDAC_FP_HVALID_END) + 1;
+  ScreenHeight = *((PULONG) NV2A_RAMDAC_FP_VVALID_END) + 1;
+  /* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
+  BytesPerPixel = 8 * (((NvGetCrtc(0x19) & 0xE0) << 3) | (NvGetCrtc(0x13) & 0xFF)) / ScreenWidth;
+  if (BytesPerPixel == 4)
+  {
+    ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel - 1);
+  }
+  else
+  {
+    ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel);
+  }
   Delta = (ScreenWidth * BytesPerPixel + 3) & ~ 0x3;
 
-  XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
+  /* Verify screen resolution */
+  ASSERT(ScreenWidth > 1);
+  ASSERT(ScreenHeight > 1);
+  ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
+  /* Verify that screen fits framebuffer size */
+  ASSERT(ScreenWidth * ScreenHeight * BytesPerPixel <= FrameBufferSize);
 
-  /* Tell the nVidia controller about the framebuffer */
-  *((PULONG) 0xfd600800) = (ULONG) FrameBuffer;
+  XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
 }
 
 VIDEODISPLAYMODE
@@ -180,6 +232,12 @@ XboxVideoGetBufferSize(VOID)
   return (ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT * (ScreenWidth / CHAR_WIDTH) * 2;
 }
 
+VOID
+XboxVideoGetFontsFromFirmware(PULONG RomFontPointers)
+{
+    TRACE("XboxVideoGetFontsFromFirmware(): UNIMPLEMENTED\n");
+}
+
 VOID
 XboxVideoSetTextCursorPosition(UCHAR X, UCHAR Y)
 {
@@ -227,22 +285,23 @@ XboxVideoGetPaletteColor(UCHAR Color, UCHAR* Red, UCHAR* Green, UCHAR* Blue)
 }
 
 VOID
-XboxVideoSync()
+XboxVideoSync(VOID)
 {
   /* Not supported */
 }
 
 VOID
-XboxBeep()
+XboxBeep(VOID)
 {
     /* Call PC version */
     PcBeep();
 }
 
 VOID
-XboxVideoPrepareForReactOS(IN BOOLEAN Setup)
+XboxVideoPrepareForReactOS(VOID)
 {
-  XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
+    XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
+    XboxVideoHideShowTextCursor(FALSE);
 }
 
 /* EOF */