https://git.reactos.org/?p=reactos.git;a=commitdiff;h=fa1ec0a2ed44fd4e5e05fec85450940281481ce9

commit fa1ec0a2ed44fd4e5e05fec85450940281481ce9
Author:     Stanislav Motylkov <x86co...@gmail.com>
AuthorDate: Tue May 12 17:32:37 2020 +0300
Commit:     Stanislav Motylkov <x86co...@gmail.com>
CommitDate: Sun May 17 19:18:32 2020 +0300

    [BOOTVID][HALXBOX] Implement boot video driver for Xbox (#2774)
    
    Also make HalpBiosDisplayReset() function always return FALSE,
    because we don't have a BIOS on Xbox.
    
    CORE-16216 CORE-16219
---
 drivers/base/bootvid/CMakeLists.txt      |   9 +
 drivers/base/bootvid/bootvid.rc          |   2 +
 drivers/base/bootvid/i386/xbox/bootvid.c | 441 +++++++++++++++++++++++++++++++
 drivers/base/bootvid/i386/xbox/nv2a.h    |  63 +++++
 drivers/base/bootvid/precomp.h           |   2 +
 hal/halx86/generic/bios.c                |   4 +
 6 files changed, 521 insertions(+)

diff --git a/drivers/base/bootvid/CMakeLists.txt 
b/drivers/base/bootvid/CMakeLists.txt
index 033a37c53ef..d9f1819478b 100644
--- a/drivers/base/bootvid/CMakeLists.txt
+++ b/drivers/base/bootvid/CMakeLists.txt
@@ -4,15 +4,24 @@ spec2def(bootvid.dll bootvid.spec ADD_IMPORTLIB)
 if((ARCH STREQUAL "i386") OR (ARCH STREQUAL "amd64"))
     if(SARCH STREQUAL "pc98")
         list(APPEND SOURCE
+            i386/pc98/pc98.h
             i386/pc98/bootvid.c)
+    elseif(SARCH STREQUAL "xbox")
+        list(APPEND SOURCE
+            i386/xbox/nv2a.h
+            i386/xbox/bootvid.c)
     else()
         list(APPEND SOURCE
+            i386/pc/pc.h
+            i386/pc/cmdcnst.h
             i386/pc/bootvid.c
             i386/pc/bootdata.c
+            i386/pc/vga.h
             i386/pc/vga.c)
     endif()
 elseif(ARCH STREQUAL "arm")
     list(APPEND SOURCE
+        arm/arm.h
         arm/bootvid.c)
 endif()
 
diff --git a/drivers/base/bootvid/bootvid.rc b/drivers/base/bootvid/bootvid.rc
index 18d91d14650..8706fe26d69 100644
--- a/drivers/base/bootvid/bootvid.rc
+++ b/drivers/base/bootvid/bootvid.rc
@@ -2,6 +2,8 @@
 
 #if defined(SARCH_PC98)
 #define REACTOS_STR_FILE_DESCRIPTION  "NEC PC-98 Boot Video Driver"
+#elif defined(SARCH_XBOX)
+#define REACTOS_STR_FILE_DESCRIPTION  "Original Xbox Boot Video Driver"
 #else
 #define REACTOS_STR_FILE_DESCRIPTION  "VGA Boot Driver"
 #endif
diff --git a/drivers/base/bootvid/i386/xbox/bootvid.c 
b/drivers/base/bootvid/i386/xbox/bootvid.c
new file mode 100644
index 00000000000..5fddab54769
--- /dev/null
+++ b/drivers/base/bootvid/i386/xbox/bootvid.c
@@ -0,0 +1,441 @@
+/*
+ * PROJECT:     ReactOS Boot Video Driver for Original Xbox
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Main file
+ * COPYRIGHT:   Copyright 2004 Gé van Geldorp (g...@reactos.org)
+ *              Copyright 2005 Filip Navara (nava...@reactos.org)
+ *              Copyright 2020 Stanislav Motylkov (x86co...@gmail.com)
+ */
+
+#include "precomp.h"
+
+#include <debug.h>
+
+/* GLOBALS 
********************************************************************/
+
+static ULONG_PTR FrameBufferStart = 0;
+static ULONG FrameBufferWidth, FrameBufferHeight, PanH, PanV;
+static UCHAR BytesPerPixel;
+static RGBQUAD CachedPalette[BV_MAX_COLORS];
+static PUCHAR BackBuffer = NULL;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+static UCHAR
+NvGetCrtc(
+    ULONG Base,
+    UCHAR Index)
+{
+    WRITE_REGISTER_UCHAR((PUCHAR)(Base + NV2A_CRTC_REGISTER_INDEX), Index);
+    return READ_REGISTER_UCHAR((PUCHAR)(Base + NV2A_CRTC_REGISTER_VALUE));
+}
+
+static UCHAR
+NvGetBytesPerPixel(
+    ULONG Base,
+    ULONG ScreenWidth)
+{
+    /* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
+    UCHAR BytesPerPixel = 8 * (((NvGetCrtc(Base, 0x19) & 0xE0) << 3) | 
(NvGetCrtc(Base, 0x13) & 0xFF)) / ScreenWidth;
+
+    if (BytesPerPixel == 4)
+    {
+        ASSERT((NvGetCrtc(Base, 0x28) & 0xF) == BytesPerPixel - 1);
+    }
+    else
+    {
+        ASSERT((NvGetCrtc(Base, 0x28) & 0xF) == BytesPerPixel);
+    }
+
+    return BytesPerPixel;
+}
+
+static VOID
+ApplyPalette(VOID)
+{
+    PULONG Frame = (PULONG)FrameBufferStart;
+    ULONG x, y;
+
+    /* Top panning */
+    for (x = 0; x < PanV * FrameBufferWidth; x++)
+    {
+        *Frame++ = CachedPalette[0];
+    }
+
+    /* Left panning */
+    for (y = 0; y < SCREEN_HEIGHT; y++)
+    {
+        Frame = (PULONG)(FrameBufferStart + FB_OFFSET(-PanH, y));
+
+        for (x = 0; x < PanH; x++)
+        {
+            *Frame++ = CachedPalette[0];
+        }
+    }
+
+    /* Screen redraw */
+    PUCHAR Back = BackBuffer;
+    for (y = 0; y < SCREEN_HEIGHT; y++)
+    {
+        Frame = (PULONG)(FrameBufferStart + FB_OFFSET(0, y));
+
+        for (x = 0; x < SCREEN_WIDTH; x++)
+        {
+            *Frame++ = CachedPalette[*Back++];
+        }
+    }
+
+    /* Right panning */
+    for (y = 0; y < SCREEN_HEIGHT; y++)
+    {
+        Frame = (PULONG)(FrameBufferStart + FB_OFFSET(SCREEN_WIDTH, y));
+
+        for (x = 0; x < PanH; x++)
+        {
+            *Frame++ = CachedPalette[0];
+        }
+    }
+
+    /* Bottom panning */
+    Frame = (PULONG)(FrameBufferStart + FB_OFFSET(-PanH, SCREEN_HEIGHT));
+    for (x = 0; x < PanV * FrameBufferWidth; x++)
+    {
+        *Frame++ = CachedPalette[0];
+    }
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+BOOLEAN
+NTAPI
+VidInitialize(
+    _In_ BOOLEAN SetMode)
+{
+    BOOLEAN Result = FALSE;
+
+    /* FIXME: Add platform check */
+    /* 1. Access PCI device 1:0:0 */
+    /* 2. Check if device ID is 10DE:02A0 */
+
+    /* FIXME: Get device MMIO ranges from PCI */
+    PHYSICAL_ADDRESS PhysControlStart = {.QuadPart = 0xFD000000};
+    PHYSICAL_ADDRESS PhysFrameBufferStart = {.QuadPart = 0xF0000000};
+    ULONG ControlLength = 16 * 1024 * 1024;
+
+    ULONG_PTR ControlStart = (ULONG_PTR)MmMapIoSpace(PhysControlStart, 
ControlLength, MmNonCached);
+    if (!ControlStart)
+    {
+        DPRINT1("Out of memory!\n");
+        return FALSE;
+    }
+
+    ULONG_PTR FrameBuffer = READ_REGISTER_ULONG((PULONG)(ControlStart + 
NV2A_CONTROL_FRAMEBUFFER_ADDRESS_OFFSET));
+    FrameBufferWidth = READ_REGISTER_ULONG((PULONG)(ControlStart + 
NV2A_RAMDAC_FP_HVALID_END)) + 1;
+    FrameBufferHeight = READ_REGISTER_ULONG((PULONG)(ControlStart + 
NV2A_RAMDAC_FP_VVALID_END)) + 1;
+
+    FrameBuffer &= 0x0FFFFFFF;
+    if (FrameBuffer != 0x3C00000 && FrameBuffer != 0x7C00000)
+    {
+        /* Check framebuffer address (high 4 MB of either 64 or 128 MB RAM) */
+        DPRINT1("Non-standard framebuffer address 0x%p\n", FrameBuffer);
+    }
+    /* Verify that framebuffer address is page-aligned */
+    ASSERT(FrameBuffer % PAGE_SIZE == 0);
+
+    if (FrameBufferWidth < SCREEN_WIDTH || FrameBufferHeight < SCREEN_HEIGHT)
+    {
+        DPRINT1("Unsupported screen resolution!\n");
+        goto cleanup;
+    }
+
+    BytesPerPixel = NvGetBytesPerPixel(ControlStart, FrameBufferWidth);
+    ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
+
+    if (BytesPerPixel != 4)
+    {
+        DPRINT1("Unsupported BytesPerPixel = %d\n", BytesPerPixel);
+        goto cleanup;
+    }
+
+    /* Calculate panning values */
+    PanH = (FrameBufferWidth - SCREEN_WIDTH) / 2;
+    PanV = (FrameBufferHeight - SCREEN_HEIGHT) / 2;
+
+    /* Verify that screen fits framebuffer size */
+    ULONG FrameBufferSize = FrameBufferWidth * FrameBufferHeight * 
BytesPerPixel;
+
+    /* FIXME: obtain fb size from firmware somehow (Cromwell reserves high 4 
MB of RAM) */
+    if (FrameBufferSize > NV2A_VIDEO_MEMORY_SIZE)
+    {
+        DPRINT1("Current screen resolution exceeds video memory bounds!\n");
+        goto cleanup;
+    }
+
+    /*
+     * Reserve off-screen area for the backbuffer that contains 8-bit indexed
+     * color screen image, plus preserved row data.
+     */
+    ULONG BackBufferSize = SCREEN_WIDTH * (SCREEN_HEIGHT + BOOTCHAR_HEIGHT + 
1);
+
+    /* Make sure there is enough video memory for backbuffer */
+    if (NV2A_VIDEO_MEMORY_SIZE - FrameBufferSize < BackBufferSize)
+    {
+        DPRINT1("Out of memory!\n");
+        goto cleanup;
+    }
+
+    /* Return the address back to GPU memory mapped I/O */
+    PhysFrameBufferStart.QuadPart += FrameBuffer;
+    FrameBufferStart = (ULONG_PTR)MmMapIoSpace(PhysFrameBufferStart, 
NV2A_VIDEO_MEMORY_SIZE, MmNonCached);
+    if (!FrameBufferStart)
+    {
+        DPRINT1("Out of memory!\n");
+        goto cleanup;
+    }
+
+    Result = TRUE;
+
+    /* Place backbuffer in the hidden part of framebuffer */
+    BackBuffer = (PUCHAR)(FrameBufferStart + NV2A_VIDEO_MEMORY_SIZE - 
BackBufferSize);
+
+    /* Now check if we have to set the mode */
+    if (SetMode)
+        VidResetDisplay(TRUE);
+
+cleanup:
+    if (ControlStart)
+        MmUnmapIoSpace((PVOID)ControlStart, ControlLength);
+
+    /* Video is ready */
+    return Result;
+}
+
+VOID
+NTAPI
+VidCleanUp(VOID)
+{
+    /* Just fill the screen black */
+    VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 
BV_COLOR_BLACK);
+}
+
+VOID
+NTAPI
+VidResetDisplay(
+    _In_ BOOLEAN HalReset)
+{
+    /* Clear the current position */
+    VidpCurrentX = 0;
+    VidpCurrentY = 0;
+
+    /* Clear the screen with HAL if we were asked to */
+    if (HalReset)
+        HalResetDisplay();
+
+    /* Re-initialize the palette and fill the screen black */
+    RtlZeroMemory((PULONG)FrameBufferStart, NV2A_VIDEO_MEMORY_SIZE);
+    InitializePalette();
+    VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 
BV_COLOR_BLACK);
+}
+
+VOID
+NTAPI
+InitPaletteWithTable(
+    _In_ PULONG Table,
+    _In_ ULONG Count)
+{
+    PULONG Entry = Table;
+
+    for (ULONG i = 0; i < Count; i++, Entry++)
+    {
+        CachedPalette[i] = *Entry | 0xFF000000;
+    }
+    ApplyPalette();
+}
+
+VOID
+PrepareForSetPixel(VOID)
+{
+    /* Nothing to prepare */
+    NOTHING;
+}
+
+VOID
+SetPixel(
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ UCHAR Color)
+{
+    PUCHAR Back = BackBuffer + BB_OFFSET(Left, Top);
+    PULONG Frame = (PULONG)(FrameBufferStart + FB_OFFSET(Left, Top));
+
+    *Back = Color;
+    *Frame = CachedPalette[Color];
+}
+
+VOID
+NTAPI
+PreserveRow(
+    _In_ ULONG CurrentTop,
+    _In_ ULONG TopDelta,
+    _In_ BOOLEAN Restore)
+{
+    PUCHAR NewPosition, OldPosition;
+
+    /* Calculate the position in memory for the row */
+    if (Restore)
+    {
+        /* Restore the row by copying back the contents saved off-screen */
+        NewPosition = BackBuffer + BB_OFFSET(0, CurrentTop);
+        OldPosition = BackBuffer + BB_OFFSET(0, SCREEN_HEIGHT);
+    }
+    else
+    {
+        /* Preserve the row by saving its contents off-screen */
+        NewPosition = BackBuffer + BB_OFFSET(0, SCREEN_HEIGHT);
+        OldPosition = BackBuffer + BB_OFFSET(0, CurrentTop);
+    }
+
+    /* Set the count and loop every pixel of backbuffer */
+    ULONG Count = TopDelta * SCREEN_WIDTH;
+
+    RtlCopyMemory(NewPosition, OldPosition, Count);
+
+    if (Restore)
+    {
+        NewPosition = BackBuffer + BB_OFFSET(0, CurrentTop);
+
+        /* Set the count and loop every pixel of framebuffer */
+        for (ULONG y = 0; y < TopDelta; y++)
+        {
+            PULONG Frame = (PULONG)(FrameBufferStart + FB_OFFSET(0, CurrentTop 
+ y));
+
+            Count = SCREEN_WIDTH;
+            while (Count--)
+            {
+                *Frame++ = CachedPalette[*NewPosition++];
+            }
+        }
+    }
+}
+
+VOID
+NTAPI
+DoScroll(
+    _In_ ULONG Scroll)
+{
+    ULONG RowSize = VidpScrollRegion[2] - VidpScrollRegion[0] + 1;
+
+    /* Calculate the position in memory for the row */
+    PUCHAR OldPosition = BackBuffer + BB_OFFSET(VidpScrollRegion[0], 
VidpScrollRegion[1] + Scroll);
+    PUCHAR NewPosition = BackBuffer + BB_OFFSET(VidpScrollRegion[0], 
VidpScrollRegion[1]);
+
+    /* Start loop */
+    for (ULONG Top = VidpScrollRegion[1]; Top <= VidpScrollRegion[3]; ++Top)
+    {
+        ULONG i;
+
+        /* Scroll the row */
+        RtlCopyMemory(NewPosition, OldPosition, RowSize);
+
+        PULONG Frame = (PULONG)(FrameBufferStart + 
FB_OFFSET(VidpScrollRegion[0], Top));
+
+        for (i = 0; i < RowSize; ++i)
+            Frame[i] = CachedPalette[NewPosition[i]];
+
+        OldPosition += SCREEN_WIDTH;
+        NewPosition += SCREEN_WIDTH;
+    }
+}
+
+VOID
+NTAPI
+DisplayCharacter(
+    _In_ CHAR Character,
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ ULONG TextColor,
+    _In_ ULONG BackColor)
+{
+    /* Get the font and pixel pointer */
+    PUCHAR FontChar = GetFontPtr(Character);
+
+    /* Loop each pixel height */
+    for (ULONG y = Top; y < Top + BOOTCHAR_HEIGHT; y++, FontChar += 
FONT_PTR_DELTA)
+    {
+        /* Loop each pixel width */
+        ULONG x = Left;
+
+        for (UCHAR bit = 1 << (BOOTCHAR_WIDTH - 1); bit > 0; bit >>= 1, x++)
+        {
+            /* Check if we should draw this pixel */
+            if (*FontChar & bit)
+            {
+                /* We do, use the given Text Color */
+                SetPixel(x, y, (UCHAR)TextColor);
+            }
+            else if (BackColor < BV_COLOR_NONE)
+            {
+                /*
+                 * This is a background pixel. We're drawing it
+                 * unless it's transparent.
+                 */
+                SetPixel(x, y, (UCHAR)BackColor);
+            }
+        }
+    }
+}
+
+VOID
+NTAPI
+VidSolidColorFill(
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ ULONG Right,
+    _In_ ULONG Bottom,
+    _In_ UCHAR Color)
+{
+    while (Top <= Bottom)
+    {
+        PUCHAR Back = BackBuffer + BB_OFFSET(Left, Top);
+        PULONG Frame = (PULONG)(FrameBufferStart + FB_OFFSET(Left, Top));
+        ULONG L = Left;
+
+        while (L++ <= Right)
+        {
+            *Back++ = Color;
+            *Frame++ = CachedPalette[Color];
+        }
+        Top++;
+    }
+}
+
+VOID
+NTAPI
+VidScreenToBufferBlt(
+    _Out_ PUCHAR Buffer,
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ ULONG Width,
+    _In_ ULONG Height,
+    _In_ ULONG Delta)
+{
+    /* Clear the destination buffer */
+    RtlZeroMemory(Buffer, Delta * Height);
+
+    /* Start the outer Y height loop */
+    for (ULONG y = 0; y < Height; y++)
+    {
+        /* Set current scanline */
+        PUCHAR Back = BackBuffer + BB_OFFSET(Left, Top + y);
+        PUCHAR Buf = Buffer + y * Delta;
+
+        /* Start the X inner loop */
+        for (ULONG x = 0; x < Width; x += 2)
+        {
+            /* Read the current value */
+            *Buf = (*Back++ & 0xF) << 4;
+            *Buf |= *Back++ & 0xF;
+            Buf++;
+        }
+    }
+}
diff --git a/drivers/base/bootvid/i386/xbox/nv2a.h 
b/drivers/base/bootvid/i386/xbox/nv2a.h
new file mode 100644
index 00000000000..e7581fee646
--- /dev/null
+++ b/drivers/base/bootvid/i386/xbox/nv2a.h
@@ -0,0 +1,63 @@
+/*
+ * PROJECT:     ReactOS Boot Video Driver for Original Xbox
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Arch-specific header file
+ * COPYRIGHT:   Copyright 2004 Gé van Geldorp (g...@reactos.org)
+ *              Copyright 2005 Filip Navara (nava...@reactos.org)
+ *              Copyright 2020 Stanislav Motylkov (x86co...@gmail.com)
+ */
+
+#ifndef _BOOTVID_NV2A_H_
+#define _BOOTVID_NV2A_H_
+
+#pragma once
+
+/* FIXME: obtain fb size from firmware somehow (Cromwell reserves high 4 MB of 
RAM) */
+#define NV2A_VIDEO_MEMORY_SIZE    (4 * 1024 * 1024)
+
+#define NV2A_CONTROL_FRAMEBUFFER_ADDRESS_OFFSET 0x600800
+#define NV2A_CRTC_REGISTER_INDEX                0x6013D4
+#define NV2A_CRTC_REGISTER_VALUE                0x6013D5
+#define NV2A_RAMDAC_FP_HVALID_END               0x680838
+#define NV2A_RAMDAC_FP_VVALID_END               0x680818
+
+#define BB_OFFSET(x, y)    ((y) * SCREEN_WIDTH + (x))
+#define FB_OFFSET(x, y)    (((PanV + (y)) * FrameBufferWidth + PanH + (x)) * 
BytesPerPixel)
+
+VOID
+NTAPI
+InitPaletteWithTable(
+    _In_ PULONG Table,
+    _In_ ULONG Count);
+
+VOID
+PrepareForSetPixel(VOID);
+
+VOID
+SetPixel(
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ UCHAR Color);
+
+VOID
+NTAPI
+PreserveRow(
+    _In_ ULONG CurrentTop,
+    _In_ ULONG TopDelta,
+    _In_ BOOLEAN Restore);
+
+VOID
+NTAPI
+DoScroll(
+    _In_ ULONG Scroll);
+
+VOID
+NTAPI
+DisplayCharacter(
+    _In_ CHAR Character,
+    _In_ ULONG Left,
+    _In_ ULONG Top,
+    _In_ ULONG TextColor,
+    _In_ ULONG BackColor);
+
+#endif /* _BOOTVID_NV2A_H_ */
diff --git a/drivers/base/bootvid/precomp.h b/drivers/base/bootvid/precomp.h
index a5a27f3ead2..bf11f82473b 100644
--- a/drivers/base/bootvid/precomp.h
+++ b/drivers/base/bootvid/precomp.h
@@ -9,6 +9,8 @@
 #if defined(_M_IX86) || defined(_M_AMD64)
 #if defined(SARCH_PC98)
 #include "i386/pc98/pc98.h"
+#elif defined(SARCH_XBOX)
+#include "i386/xbox/nv2a.h"
 #else
 #include "i386/pc/vga.h"
 #include "i386/pc/pc.h"
diff --git a/hal/halx86/generic/bios.c b/hal/halx86/generic/bios.c
index 85a9d5b37d5..2fe73aa15e5 100644
--- a/hal/halx86/generic/bios.c
+++ b/hal/halx86/generic/bios.c
@@ -645,6 +645,9 @@ BOOLEAN
 NTAPI
 HalpBiosDisplayReset(VOID)
 {
+#ifdef SARCH_XBOX
+    return FALSE;
+#else
     ULONG Flags;
     PHARDWARE_PTE IdtPte;
     BOOLEAN RestoreWriteProtection = FALSE;
@@ -709,6 +712,7 @@ HalpBiosDisplayReset(VOID)
     //
     __writeeflags(Flags);
     return TRUE;
+#endif
 }
 #endif
 

Reply via email to