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

commit a33719500c71638da03e83e0c9914ec9c9fe3c27
Author:     Hervé Poussineau <[email protected]>
AuthorDate: Mon Oct 17 12:00:00 2022 +0200
Commit:     hpoussin <[email protected]>
CommitDate: Mon Oct 17 18:20:22 2022 +0200

    [BOCHSMP] Add driver for QEMU and Bochs graphic card
---
 boot/bootdata/hivesys.inf                      |   3 +
 win32ss/drivers/miniport/CMakeLists.txt        |   1 +
 win32ss/drivers/miniport/bochs/CMakeLists.txt  |  12 +
 win32ss/drivers/miniport/bochs/bochsmp.c       | 766 +++++++++++++++++++++++++
 win32ss/drivers/miniport/bochs/bochsmp.h       |  69 +++
 win32ss/drivers/miniport/bochs/bochsmp.inf     |  62 ++
 win32ss/drivers/miniport/bochs/bochsmp.rc      |   5 +
 win32ss/drivers/miniport/bochs/bochsmp_reg.inf |  13 +
 8 files changed, 931 insertions(+)

diff --git a/boot/bootdata/hivesys.inf b/boot/bootdata/hivesys.inf
index 45c3d6e6446..3bc5eb62c63 100644
--- a/boot/bootdata/hivesys.inf
+++ b/boot/bootdata/hivesys.inf
@@ -83,6 +83,9 @@ 
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\HID_DEVICE_SYSTEM_
 
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\HID_DEVICE_SYSTEM_MOUSE","Service",0x00000000,"mouhid"
 
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\HID_DEVICE_SYSTEM_MOUSE","ClassGUID",0x00000000,"{4D36E96F-E325-11CE-BFC1-08002BE10318}"
 
+HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#VEN_1234&DEV_1111","Service",0x00000000,"bochsmp"
+HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#VEN_1234&DEV_1111","ClassGUID",0x00000000,"{4D36E968-E325-11CE-BFC1-08002BE10318}"
+
 
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#CC_0000","Service",0x00000000,"vga"
 
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#CC_0000","ClassGUID",0x00000000,"{4D36E968-E325-11CE-BFC1-08002BE10318}"
 
diff --git a/win32ss/drivers/miniport/CMakeLists.txt 
b/win32ss/drivers/miniport/CMakeLists.txt
index 4e6d357051d..e5996f9b2e7 100644
--- a/win32ss/drivers/miniport/CMakeLists.txt
+++ b/win32ss/drivers/miniport/CMakeLists.txt
@@ -1,4 +1,5 @@
 
+add_subdirectory(bochs)
 add_subdirectory(vbe)
 add_subdirectory(vga)
 #add_subdirectory(vga_new)
diff --git a/win32ss/drivers/miniport/bochs/CMakeLists.txt 
b/win32ss/drivers/miniport/bochs/CMakeLists.txt
new file mode 100644
index 00000000000..aff939aa26e
--- /dev/null
+++ b/win32ss/drivers/miniport/bochs/CMakeLists.txt
@@ -0,0 +1,12 @@
+list(APPEND SOURCE
+    bochsmp.c
+    bochsmp.h)
+
+add_library(bochsmp MODULE ${SOURCE} bochsmp.rc)
+set_module_type(bochsmp kernelmodedriver)
+add_importlibs(bochsmp videoprt)
+target_link_libraries(bochsmp libcntpr)
+add_pch(bochsmp bochsmp.h SOURCE)
+add_cd_file(TARGET bochsmp DESTINATION reactos/system32/drivers FOR all)
+add_registry_inf(bochsmp_reg.inf)
+add_driver_inf(bochsmp bochsmp.inf)
diff --git a/win32ss/drivers/miniport/bochs/bochsmp.c 
b/win32ss/drivers/miniport/bochs/bochsmp.c
new file mode 100644
index 00000000000..220c15336f3
--- /dev/null
+++ b/win32ss/drivers/miniport/bochs/bochsmp.c
@@ -0,0 +1,766 @@
+/*
+ * PROJECT:     ReactOS Bochs graphics card driver
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Bochs graphics card driver
+ * COPYRIGHT:   Copyright 2022 Hervé Poussineau <[email protected]>
+ */
+
+#include "bochsmp.h"
+
+static const BOCHS_SIZE BochsAvailableResolutions[] = {
+    { 640, 480 },   // VGA
+    { 800, 600 },   // SVGA
+    { 1024, 600 },  // WSVGA
+    { 1024, 768 },  // XGA
+    { 1152, 864 },  // XGA+
+    { 1280, 720 },  // WXGA-H
+    { 1280, 768 },  // WXGA
+    { 1280, 960 },  // SXGA-
+    { 1280, 1024 }, // SXGA
+    { 1368, 768 },  // HD ready
+    { 1400, 1050 }, // SXGA+
+    { 1440, 900 },  // WSXGA
+    { 1600, 900 },  // HD+
+    { 1600, 1200 }, // UXGA
+    { 1680, 1050 }, // WSXGA+
+    { 1920, 1080 }, // FHD
+    { 2048, 1536 }, // QXGA
+    { 2560, 1440 }, // WQHD
+    { 2560, 1600 }, // WQXGA
+    { 2560, 2048 }, // QSXGA
+    { 2800, 2100 }, // QSXGA+
+    { 3200, 2400 }, // QUXGA
+    { 3840, 2160 }, // 4K UHD-1
+};
+
+CODE_SEG("PAGE")
+static VOID
+BochsFreeResources(
+    _Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension)
+{
+    if (DeviceExtension->AvailableModeInfo)
+    {
+        VideoPortFreePool(DeviceExtension, DeviceExtension->AvailableModeInfo);
+        DeviceExtension->AvailableModeInfo = NULL;
+    }
+}
+
+CODE_SEG("PAGE")
+static VOID
+BochsWriteDispI(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _In_ ULONG Index,
+    _In_ USHORT Value)
+{
+    if (DeviceExtension->IoPorts.RangeInIoSpace)
+    {
+        VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - 
VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_INDEX), Index);
+        VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - 
VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_DATA), Value);
+    }
+    else
+    {
+        VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped 
+ 0x500 + Index * 2), Value);
+    }
+}
+
+CODE_SEG("PAGE")
+static USHORT
+BochsReadDispI(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _In_ ULONG Index)
+{
+    if (DeviceExtension->IoPorts.RangeInIoSpace)
+    {
+        VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - 
VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_INDEX), Index);
+        return 
VideoPortReadPortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - 
VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_DATA));
+    }
+    else
+    {
+        return 
VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x500 + 
Index * 2));
+    }
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsWriteDispIAndCheck(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _In_ ULONG Index,
+    _In_ USHORT Value)
+{
+    BochsWriteDispI(DeviceExtension, Index, Value);
+    return BochsReadDispI(DeviceExtension, Index) == Value;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsInitializeSuitableModeInfo(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _In_ ULONG PotentialModeCount)
+{
+    ULONG i, ModeCount = 0;
+
+    for (i = 0; i < ARRAYSIZE(BochsAvailableResolutions) && ModeCount < 
PotentialModeCount; i++)
+    {
+        if (BochsAvailableResolutions[i].XResolution > 
DeviceExtension->MaxXResolution)
+            continue;
+        if (BochsAvailableResolutions[i].YResolution > 
DeviceExtension->MaxYResolution)
+            continue;
+        if (BochsAvailableResolutions[i].XResolution * 
BochsAvailableResolutions[i].YResolution * 4 > DeviceExtension->VramSize64K * 
64 * 1024)
+            continue;
+        DeviceExtension->AvailableModeInfo[ModeCount++] = 
BochsAvailableResolutions[i];
+    }
+
+    if (ModeCount == 0)
+    {
+        VideoDebugPrint((Error, "Bochs: no suitable modes available!\n"));
+        return FALSE;
+    }
+
+    DeviceExtension->AvailableModeCount = ModeCount;
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsGetControllerInfo(
+    _Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension)
+{
+    USHORT Version;
+    WCHAR ChipType[5];
+    ULONG SizeInBytes;
+
+    /* Detect DISPI version */
+    for (Version = VBE_DISPI_ID5; Version >= VBE_DISPI_ID0; Version--)
+    {
+        if (BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_ID, 
Version))
+            break;
+    }
+    if (Version < VBE_DISPI_ID0)
+    {
+        VideoDebugPrint((Error, "Bochs: VBE extension signature incorrect\n"));
+        return FALSE;
+    }
+    VideoDebugPrint((Error, "Bochs: detected version 0x%04x\n", Version));
+    if (Version < VBE_DISPI_ID2)
+    {
+        /* Too old (no 32 bpp support, no linear frame buffer) */
+        VideoDebugPrint((Error, "Bochs: VBE extension too old (0x%04x)\n", 
Version));
+        return FALSE;
+    }
+
+    if (Version <= VBE_DISPI_ID2)
+    {
+        DeviceExtension->MaxXResolution = 1024;
+        DeviceExtension->MaxYResolution = 768;
+    }
+    else
+    {
+        BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, 
VBE_DISPI_GETCAPS);
+        DeviceExtension->MaxXResolution = BochsReadDispI(DeviceExtension, 
VBE_DISPI_INDEX_XRES);
+        DeviceExtension->MaxYResolution = BochsReadDispI(DeviceExtension, 
VBE_DISPI_INDEX_YRES);
+        BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, 
VBE_DISPI_DISABLED);
+        /* Workaround bug in QEMU bochs-display */
+        if (DeviceExtension->MaxXResolution == 0 && 
DeviceExtension->MaxYResolution == 0)
+        {
+            DeviceExtension->MaxXResolution = 1024;
+            DeviceExtension->MaxYResolution = 768;
+        }
+    }
+    if (Version < VBE_DISPI_ID4)
+    {
+        DeviceExtension->VramSize64K = 4 * 1024 / 64; /* 4 MB */
+    }
+    else if (Version == VBE_DISPI_ID4)
+    {
+        DeviceExtension->VramSize64K = 8 * 1024 / 64; /* 8 MB */
+    }
+    else
+    {
+        DeviceExtension->VramSize64K = BochsReadDispI(DeviceExtension, 
VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
+    }
+    VideoDebugPrint((Info, "Bochs: capabilities %dx%d (%d MB)\n",
+                     DeviceExtension->MaxXResolution,
+                     DeviceExtension->MaxYResolution,
+                     DeviceExtension->VramSize64K * 64 / 1024));
+
+    /* Store information in registry */
+#define HEX(c) (((c) >= 0 && (c) <= 9) ? (c) + L'0' : (c) - 10 + L'A')
+    ChipType[0] = HEX((Version >> 12) & 0xf);
+    ChipType[1] = HEX((Version >> 8) & 0xf);
+    ChipType[2] = HEX((Version >> 4) & 0xf);
+    ChipType[3] = HEX(Version & 0xf);
+    ChipType[4] = UNICODE_NULL;
+    VideoPortSetRegistryParameters(DeviceExtension, 
L"HardwareInformation.ChipType", ChipType, sizeof(ChipType));
+    SizeInBytes = DeviceExtension->VramSize64K * 64 * 1024;
+    VideoPortSetRegistryParameters(DeviceExtension, 
L"HardwareInformation.MemorySize", &SizeInBytes, sizeof(SizeInBytes));
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static VOID
+BochsGetModeInfo(
+    _In_ PBOCHS_SIZE AvailableModeInfo,
+    _Out_ PVIDEO_MODE_INFORMATION ModeInfo,
+    _In_ ULONG Index)
+{
+    VideoDebugPrint((Info, "Bochs: Filling details of mode #%d\n", Index));
+
+    ModeInfo->Length = sizeof(*ModeInfo);
+    ModeInfo->ModeIndex = Index;
+    ModeInfo->VisScreenWidth = AvailableModeInfo->XResolution;
+    ModeInfo->VisScreenHeight = AvailableModeInfo->YResolution;
+    ModeInfo->ScreenStride = AvailableModeInfo->XResolution * 4;
+    ModeInfo->NumberOfPlanes = 1;
+    ModeInfo->BitsPerPlane = 32;
+    ModeInfo->Frequency = 60;
+
+    /* 960 DPI appears to be common */
+    ModeInfo->XMillimeter = AvailableModeInfo->XResolution * 254 / 960;
+    ModeInfo->YMillimeter = AvailableModeInfo->YResolution * 254 / 960;
+    ModeInfo->NumberRedBits = 8;
+    ModeInfo->NumberGreenBits = 8;
+    ModeInfo->NumberBlueBits = 8;
+    ModeInfo->RedMask = 0xff0000;
+    ModeInfo->GreenMask = 0x00ff00;
+    ModeInfo->BlueMask = 0x0000ff;
+
+    ModeInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | 
VIDEO_MODE_NO_OFF_SCREEN;
+    ModeInfo->VideoMemoryBitmapWidth = AvailableModeInfo->XResolution;
+    ModeInfo->VideoMemoryBitmapHeight = AvailableModeInfo->YResolution;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsMapVideoMemory(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _In_ PVIDEO_MEMORY RequestedAddress,
+    _Out_ PVIDEO_MEMORY_INFORMATION MapInformation,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    VP_STATUS Status;
+    PHYSICAL_ADDRESS VideoMemory;
+    ULONG MemSpace = VIDEO_MEMORY_SPACE_MEMORY;
+
+    VideoDebugPrint((Info, "Bochs: BochsMapVideoMemory Entry\n"));
+
+    VideoMemory = DeviceExtension->FrameBuffer.RangeStart;
+    MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
+    MapInformation->VideoRamLength = 4 *
+        
DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode].XResolution *
+        
DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode].YResolution;
+
+    Status = VideoPortMapMemory(DeviceExtension,
+                                VideoMemory,
+                                &MapInformation->VideoRamLength,
+                                &MemSpace,
+                                &MapInformation->VideoRamBase);
+    if (Status != NO_ERROR)
+    {
+        VideoDebugPrint((Error, "BochsMapVideoMemory - VideoPortMapMemory 
failed status:%x\n", Status));
+        StatusBlock->Status = Status;
+        return FALSE;
+    }
+
+    MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
+    MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
+    StatusBlock->Information = sizeof(*MapInformation);
+    StatusBlock->Status = NO_ERROR;
+
+    VideoDebugPrint((Info, "Bochs:BochsMapVideoMemory Exit VideoRamBase: %p 
VideoRamLength: 0x%x PhysBasePtr: 0x%x\n",
+                     MapInformation->VideoRamBase, 
MapInformation->VideoRamLength, (ULONG)VideoMemory.QuadPart));
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN NTAPI
+BochsUnmapVideoMemory(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _In_ PVIDEO_MEMORY VideoMemory,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    VP_STATUS Status;
+
+    VideoDebugPrint((Info, "Bochs: BochsUnmapVideoMemory Entry 
VideoRamBase:%p\n", VideoMemory->RequestedVirtualAddress));
+
+    Status = VideoPortUnmapMemory(DeviceExtension, 
VideoMemory->RequestedVirtualAddress, NULL);
+    if (Status != NO_ERROR)
+    {
+        VideoDebugPrint((Error, "Bochs: BochsUnmapVideoMemory Failed to unmap 
memory:%p Status:%x\n",
+                         VideoMemory->RequestedVirtualAddress,
+                         Status));
+    }
+
+    StatusBlock->Status = Status;
+
+    VideoDebugPrint((Info, "Bochs: BochsUnmapVideoMemory Exit status:%x\n", 
Status));
+    return (Status == NO_ERROR);
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsQueryNumAvailableModes(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _Out_ PVIDEO_NUM_MODES AvailableModes,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    AvailableModes->NumModes = DeviceExtension->AvailableModeCount;
+    AvailableModes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
+
+    StatusBlock->Information = sizeof(*AvailableModes);
+    StatusBlock->Status = NO_ERROR;
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsQueryAvailableModes(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _Out_ PVIDEO_MODE_INFORMATION ReturnedModes,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    ULONG Count;
+    PBOCHS_SIZE AvailableModeInfo;
+    PVIDEO_MODE_INFORMATION ModeInfo;
+
+    for (Count = 0, AvailableModeInfo = DeviceExtension->AvailableModeInfo, 
ModeInfo = ReturnedModes;
+        Count < DeviceExtension->AvailableModeCount;
+        Count++, AvailableModeInfo++, ModeInfo++)
+    {
+        VideoPortZeroMemory(ModeInfo, sizeof(*ModeInfo));
+        BochsGetModeInfo(AvailableModeInfo, ModeInfo, Count);
+    }
+
+    StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION) * 
DeviceExtension->AvailableModeCount;
+    StatusBlock->Status = NO_ERROR;
+
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsSetCurrentMode(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _In_ PVIDEO_MODE RequestedMode,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    PBOCHS_SIZE AvailableModeInfo;
+    /* Mask the two high-order bits, which can be set to request special 
behavior */
+    ULONG ModeRequested = RequestedMode->RequestedMode & 0x3fffffff;
+    BOOLEAN Ret;
+
+    VideoDebugPrint((Info, "Bochs:BochsSetCurrentMode Entry\n"));
+
+    if (ModeRequested >= DeviceExtension->AvailableModeCount)
+    {
+        VideoDebugPrint((Error, "Bochs: set current mode - invalid 
parameter\n"));
+        StatusBlock->Status = ERROR_INVALID_PARAMETER;
+        return FALSE;
+    }
+
+    AvailableModeInfo = &DeviceExtension->AvailableModeInfo[ModeRequested];
+
+    /* Set the mode characteristics */
+    BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, 
VBE_DISPI_DISABLED);
+    Ret = BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_XRES, 
AvailableModeInfo->XResolution) &&
+          BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_YRES, 
AvailableModeInfo->YResolution) &&
+          BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_BPP, 32);
+    /* Always enable screen, even if display settings change failed */
+    BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, 
VBE_DISPI_LFB_ENABLED | VBE_DISPI_ENABLED);
+    if (!Ret)
+    {
+        VideoDebugPrint((Error, "Bochs: failed to change mode\n"));
+        return FALSE;
+    }
+
+    /* Enable VGA (QEMU secondary-vga disables it by default) */
+    if (!DeviceExtension->IoPorts.RangeInIoSpace)
+    {
+        /* Discard AR flip-flip */
+        
(VOID)VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 
0x41A));
+        /* Enable display */
+        VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped 
+ 0x400), 0x20);
+    }
+
+    DeviceExtension->CurrentMode = (USHORT)ModeRequested;
+    StatusBlock->Status = NO_ERROR;
+
+    VideoDebugPrint((Info, "Bochs:BochsSetCurrentMode Exit Mode:%d\n", 
ModeRequested));
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsQueryCurrentMode(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _Out_ PVIDEO_MODE_INFORMATION VideoModeInfo,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    PBOCHS_SIZE AvailableModeInfo;
+
+    if (DeviceExtension->CurrentMode > DeviceExtension->AvailableModeCount)
+    {
+        StatusBlock->Status = ERROR_INVALID_PARAMETER;
+        return FALSE;
+    }
+
+    AvailableModeInfo = 
&DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode];
+    VideoPortZeroMemory(VideoModeInfo, sizeof(*VideoModeInfo));
+    BochsGetModeInfo(AvailableModeInfo, VideoModeInfo, 
DeviceExtension->CurrentMode);
+
+    StatusBlock->Information = sizeof(*VideoModeInfo);
+    StatusBlock->Status = NO_ERROR;
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsResetDevice(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    VideoDebugPrint((Info, "Bochs:BochsResetDevice Entry\n"));
+
+    StatusBlock->Status = NO_ERROR;
+
+    VideoDebugPrint((Info, "Bochs:BochsResetDevice Exit\n"));
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+static BOOLEAN
+BochsGetChildState(
+    _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
+    _Out_ PULONG pChildState,
+    _Out_ PSTATUS_BLOCK StatusBlock)
+{
+    *pChildState = VIDEO_CHILD_ACTIVE;
+
+    StatusBlock->Information = sizeof(*pChildState);
+    StatusBlock->Status = NO_ERROR;
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+VP_STATUS NTAPI
+BochsFindAdapter(
+    _In_ PVOID HwDeviceExtension,
+    _In_ PVOID HwContext,
+    _In_ PWSTR ArgumentString,
+    _In_ PVIDEO_PORT_CONFIG_INFO ConfigInfo,
+    _In_ PUCHAR Again)
+{
+    PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+    VIDEO_ACCESS_RANGE AccessRanges[2] = {0};
+
+    if (ConfigInfo->Length < sizeof(*ConfigInfo))
+        return ERROR_INVALID_PARAMETER;
+
+    if (VideoPortGetAccessRanges(DeviceExtension, 0, NULL, 
ARRAYSIZE(AccessRanges), AccessRanges, NULL, NULL, NULL) != NO_ERROR)
+    {
+        VideoDebugPrint((Error, "Bochs: failed to get access ranges\n"));
+        return ERROR_DEV_NOT_EXIST;
+    }
+
+    /* Framebuffer */
+    DeviceExtension->FrameBuffer.RangeStart = AccessRanges[0].RangeStart;
+    DeviceExtension->FrameBuffer.RangeLength = AccessRanges[0].RangeLength;
+    DeviceExtension->FrameBuffer.RangeInIoSpace = 
AccessRanges[0].RangeInIoSpace;
+
+    /* I/O ports */
+    if (AccessRanges[1].RangeLength == 0)
+    {
+        /* Set default values */
+        AccessRanges[1].RangeStart.LowPart = VBE_DISPI_IOPORT_INDEX;
+        AccessRanges[1].RangeLength = 2;
+        AccessRanges[1].RangeInIoSpace = TRUE;
+        if (VideoPortVerifyAccessRanges(DeviceExtension, 1, &AccessRanges[1]) 
!= NO_ERROR)
+        {
+            VideoDebugPrint((Error, "Bochs: failed to claim I/O range 
0x%x-0x%x\n",
+                            VBE_DISPI_IOPORT_INDEX,
+                            VBE_DISPI_IOPORT_INDEX + 1));
+            return ERROR_DEV_NOT_EXIST;
+        }
+    }
+    else if (AccessRanges[1].RangeLength != 0x1000)
+    {
+        VideoDebugPrint((Error, "Bochs: invalid access ranges (size 0x%x)\n", 
AccessRanges[1].RangeLength));
+        return ERROR_DEV_NOT_EXIST;
+    }
+    DeviceExtension->IoPorts.RangeStart = AccessRanges[1].RangeStart;
+    DeviceExtension->IoPorts.RangeLength = AccessRanges[1].RangeLength;
+    DeviceExtension->IoPorts.RangeInIoSpace = AccessRanges[1].RangeInIoSpace;
+
+    DeviceExtension->IoPorts.Mapped = VideoPortGetDeviceBase(DeviceExtension,
+                                                             
DeviceExtension->IoPorts.RangeStart,
+                                                             
DeviceExtension->IoPorts.RangeLength,
+                                                             
DeviceExtension->IoPorts.RangeInIoSpace
+                                                                 ? 
VIDEO_MEMORY_SPACE_IO
+                                                                 : 
VIDEO_MEMORY_SPACE_MEMORY);
+    if (!DeviceExtension->IoPorts.Mapped)
+    {
+        VideoDebugPrint((Error, "Bochs: failed to map dispi interface\n"));
+        return ERROR_DEV_NOT_EXIST;
+    }
+    VideoDebugPrint((Info, "Bochs: address 0x%x mapped to 0x%p\n",
+                     DeviceExtension->IoPorts.RangeStart.LowPart,
+                     DeviceExtension->IoPorts.Mapped));
+
+    return NO_ERROR;
+}
+
+CODE_SEG("PAGE")
+BOOLEAN NTAPI
+BochsInitialize(
+    _In_ PVOID HwDeviceExtension)
+{
+    ULONG PotentialModeCount = 0;
+    PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+
+    VideoDebugPrint((Info, "Bochs: BochsInitialize\n"));
+
+    if (!BochsGetControllerInfo(DeviceExtension))
+    {
+        BochsFreeResources(DeviceExtension);
+        return FALSE;
+    }
+
+    PotentialModeCount = ARRAYSIZE(BochsAvailableResolutions);
+    DeviceExtension->AvailableModeInfo = 
VideoPortAllocatePool(HwDeviceExtension,
+                                                               VpPagedPool,
+                                                               
PotentialModeCount * sizeof(BOCHS_SIZE),
+                                                               BOCHS_TAG);
+    if (!DeviceExtension->AvailableModeInfo)
+    {
+        VideoDebugPrint((Error, "Bochs: insufficient resources\n"));
+        BochsFreeResources(DeviceExtension);
+        return FALSE;
+    }
+
+    if (!BochsInitializeSuitableModeInfo(DeviceExtension, PotentialModeCount))
+    {
+        BochsFreeResources(DeviceExtension);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+CODE_SEG("PAGE")
+BOOLEAN NTAPI
+BochsStartIO(
+    _In_ PVOID HwDeviceExtension,
+    _Inout_ PVIDEO_REQUEST_PACKET RequestPacket)
+{
+    PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+
+    VideoDebugPrint((Info, "Bochs: BochsStartIO\n"));
+    RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
+
+    switch (RequestPacket->IoControlCode)
+    {
+        case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Map video memory\n"));
+            if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
+            {
+                VideoDebugPrint((Error, "BochsStartIO - invalid input 
parameter\n"));
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            if (RequestPacket->OutputBufferLength < 
sizeof(VIDEO_MEMORY_INFORMATION))
+            {
+                VideoDebugPrint((Error, "BochsStartIO - Insufficent output 
buffer\n"));
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            return BochsMapVideoMemory(DeviceExtension,
+                                       
(PVIDEO_MEMORY)RequestPacket->InputBuffer,
+                                       
(PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
+                                       RequestPacket->StatusBlock);
+        }
+
+        case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Unmap video memory\n"));
+            if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
+            {
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            return BochsUnmapVideoMemory(DeviceExtension,
+                                         
(PVIDEO_MEMORY)RequestPacket->InputBuffer,
+                                         RequestPacket->StatusBlock);
+        }
+
+        case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Query num available 
modes\n"));
+            if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
+            {
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            return BochsQueryNumAvailableModes(DeviceExtension,
+                                               
(PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
+                                               RequestPacket->StatusBlock);
+        }
+
+        case IOCTL_VIDEO_QUERY_AVAIL_MODES:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Query available modes\n"));
+            if (RequestPacket->OutputBufferLength < 
DeviceExtension->AvailableModeCount * sizeof(VIDEO_MODE_INFORMATION))
+            {
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            return BochsQueryAvailableModes(DeviceExtension,
+                                            
(PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
+                                            RequestPacket->StatusBlock);
+        }
+
+        case IOCTL_VIDEO_SET_CURRENT_MODE:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Set current mode\n"));
+            if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
+            {
+                VideoDebugPrint((Error, "Bochs: set current mode - invalid 
parameter\n"));
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            return BochsSetCurrentMode(DeviceExtension,
+                                       (PVIDEO_MODE)RequestPacket->InputBuffer,
+                                       RequestPacket->StatusBlock);
+        }
+
+        case IOCTL_VIDEO_QUERY_CURRENT_MODE:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Query current mode\n"));
+            if (RequestPacket->OutputBufferLength < 
sizeof(VIDEO_MODE_INFORMATION))
+            {
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            return BochsQueryCurrentMode(DeviceExtension,
+                                         
(PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
+                                         RequestPacket->StatusBlock);
+        }
+
+        case IOCTL_VIDEO_RESET_DEVICE:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Reset device\n"));
+            return BochsResetDevice(DeviceExtension,
+                                    RequestPacket->StatusBlock);
+        }
+
+        case IOCTL_VIDEO_GET_CHILD_STATE:
+        {
+            VideoDebugPrint((Info, "BochsStartIO - Get child state\n"));
+            if (RequestPacket->OutputBufferLength < sizeof(ULONG))
+            {
+                RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
+                return FALSE;
+            }
+            return BochsGetChildState(DeviceExtension,
+                                      (PULONG)RequestPacket->OutputBuffer,
+                                      RequestPacket->StatusBlock);
+        }
+
+        default:
+        {
+            VideoDebugPrint((Warn, "BochsStartIO - Unknown IOCTL - 0x%08x\n",
+                             RequestPacket->IoControlCode));
+            break;
+        }
+    }
+
+    return FALSE;
+}
+
+CODE_SEG("PAGE")
+VP_STATUS NTAPI
+BochsSetPowerState(
+    _In_ PVOID HwDeviceExtension,
+    _In_ ULONG HwId,
+    _In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)
+{
+    return NO_ERROR;
+}
+
+CODE_SEG("PAGE")
+VP_STATUS NTAPI
+BochsGetPowerState(
+    _In_ PVOID HwDeviceExtension,
+    _In_ ULONG HwId,
+    _Out_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)
+{
+    return ERROR_DEVICE_REINITIALIZATION_NEEDED;
+}
+
+CODE_SEG("PAGE")
+VP_STATUS NTAPI
+BochsGetVideoChildDescriptor(
+    _In_ PVOID HwDeviceExtension,
+    _In_ PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
+    _Out_ PVIDEO_CHILD_TYPE VideoChildType,
+    _Out_ PUCHAR pChildDescriptor,
+    _Out_ PULONG UId,
+    _Out_ PULONG pUnused)
+{
+    PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
+
+    VideoDebugPrint((Info, "Bochs: BochsGetVideoChildDescriptor Entry\n"));
+
+    if (ChildEnumInfo->Size < sizeof(*VideoChildType))
+        return VIDEO_ENUM_NO_MORE_DEVICES;
+
+    if (ChildEnumInfo->ChildIndex == 0)
+    {
+        /* Ignore ACPI enumerations */
+        return VIDEO_ENUM_INVALID_DEVICE;
+    }
+
+    *pUnused = 0;
+    if (ChildEnumInfo->ChildIndex == DISPLAY_ADAPTER_HW_ID)
+    {
+        *VideoChildType = VideoChip;
+        return VIDEO_ENUM_MORE_DEVICES;
+    }
+
+    if (ChildEnumInfo->ChildIndex != 1)
+        return VIDEO_ENUM_NO_MORE_DEVICES;
+
+    *UId = 0;
+    *VideoChildType = Monitor;
+
+    if (pChildDescriptor &&
+        ChildEnumInfo->ChildDescriptorSize >= VBE_EDID_SIZE &&
+        !DeviceExtension->IoPorts.RangeInIoSpace)
+    {
+        memcpy(pChildDescriptor,
+               DeviceExtension->IoPorts.Mapped,
+               VBE_EDID_SIZE);
+    }
+
+    VideoDebugPrint((Info, "Bochs: BochsGetVideoChildDescriptor Exit 
Uid:%d\n", ChildEnumInfo->ChildIndex));
+
+    return VIDEO_ENUM_MORE_DEVICES;
+}
+
+ULONG NTAPI
+DriverEntry(PVOID Context1, PVOID Context2)
+{
+    VIDEO_HW_INITIALIZATION_DATA VideoInitData;
+
+    VideoDebugPrint((Info, "Bochs: DriverEntry\n"));
+    VideoPortZeroMemory(&VideoInitData, sizeof(VideoInitData));
+    VideoInitData.HwInitDataSize = sizeof(VideoInitData);
+    VideoInitData.HwFindAdapter = BochsFindAdapter;
+    VideoInitData.HwInitialize = BochsInitialize;
+    VideoInitData.HwStartIO = BochsStartIO;
+    VideoInitData.HwDeviceExtensionSize = sizeof(BOCHS_DEVICE_EXTENSION);
+    VideoInitData.HwSetPowerState = BochsSetPowerState;
+    VideoInitData.HwGetPowerState = BochsGetPowerState;
+    VideoInitData.HwGetVideoChildDescriptor = BochsGetVideoChildDescriptor;
+
+    return VideoPortInitialize(Context1, Context2, &VideoInitData, NULL);
+}
diff --git a/win32ss/drivers/miniport/bochs/bochsmp.h 
b/win32ss/drivers/miniport/bochs/bochsmp.h
new file mode 100644
index 00000000000..b9d8cb242b7
--- /dev/null
+++ b/win32ss/drivers/miniport/bochs/bochsmp.h
@@ -0,0 +1,69 @@
+/*
+ * PROJECT:     ReactOS Bochs graphics card driver
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Bochs graphics card driver
+ * COPYRIGHT:   Copyright 2022 Hervé Poussineau <[email protected]>
+ */
+
+#ifndef BOCHS_H
+#define BOCHS_H
+
+#include <ntdef.h>
+#include <dderror.h>
+#include <miniport.h>
+#include <video.h>
+#include <devioctl.h>
+#include <section_attribs.h>
+
+#define VBE_EDID_SIZE                        0x80
+
+#define VBE_DISPI_IOPORT_INDEX               0x01CE
+#define VBE_DISPI_IOPORT_DATA                0x01CF
+#define VBE_DISPI_INDEX_ID                   0x00
+  #define VBE_DISPI_ID0                        0xB0C0
+  #define VBE_DISPI_ID1                        0xB0C1
+  #define VBE_DISPI_ID2                        0xB0C2
+  #define VBE_DISPI_ID3                        0xB0C3
+  #define VBE_DISPI_ID4                        0xB0C4
+  #define VBE_DISPI_ID5                        0xB0C5
+#define VBE_DISPI_INDEX_XRES                 0x01
+#define VBE_DISPI_INDEX_YRES                 0x02
+#define VBE_DISPI_INDEX_BPP                  0x03
+#define VBE_DISPI_INDEX_ENABLE               0x04
+  #define VBE_DISPI_DISABLED                   0x00
+  #define VBE_DISPI_ENABLED                    0x01
+  #define VBE_DISPI_GETCAPS                    0x02
+  #define VBE_DISPI_LFB_ENABLED                0x40
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K     0x0A
+
+#define BOCHS_TAG 'BCHS'
+
+typedef struct
+{
+    USHORT XResolution;
+    USHORT YResolution;
+} BOCHS_SIZE, *PBOCHS_SIZE;
+
+typedef struct
+{
+    PUCHAR Mapped;
+    PHYSICAL_ADDRESS RangeStart;
+    ULONG RangeLength;
+    UCHAR RangeInIoSpace;
+} BOCHS_ADDRESS_RANGE;
+
+typedef struct
+{
+    PBOCHS_SIZE AvailableModeInfo;
+    ULONG AvailableModeCount;
+    USHORT CurrentMode;
+
+    BOCHS_ADDRESS_RANGE FrameBuffer;
+    BOCHS_ADDRESS_RANGE IoPorts;
+
+    ULONG MaxXResolution;
+    ULONG MaxYResolution;
+    ULONG VramSize64K;
+} BOCHS_DEVICE_EXTENSION, *PBOCHS_DEVICE_EXTENSION;
+
+#endif //BOCHS_H
diff --git a/win32ss/drivers/miniport/bochs/bochsmp.inf 
b/win32ss/drivers/miniport/bochs/bochsmp.inf
new file mode 100644
index 00000000000..5b7ee4d56d7
--- /dev/null
+++ b/win32ss/drivers/miniport/bochs/bochsmp.inf
@@ -0,0 +1,62 @@
+; bochsmp.inf
+;
+; Installation file for the Bochs display adapter
+;
+[Version]
+Signature  = "$Windows NT$"
+LayoutFile = layout.inf
+Class      = Display
+ClassGUID  = {4D36E968-E325-11CE-BFC1-08002BE10318}
+Provider   = %ReactOS%
+DriverVer  = 10/17/2022,1.00
+
+[DestinationDirs]
+DefaultDestDir = 12
+Bochs.Display_CopyFiles = 11
+
+[Manufacturer]
+%Bochs% = Bochs
+
+[Bochs]
+%Bochs.DeviceDesc% = Bochs,PCI\VEN_1234&DEV_1111
+
+;---------------------------- BOCHS DRIVER ----------------------------
+
+[Bochs]
+CopyFiles = Bochs.Miniport_CopyFiles, Bochs.Display_CopyFiles
+
+[Bochs.Miniport_CopyFiles]
+bochsmp.sys
+
+[Bochs.Display_CopyFiles]
+framebuf.dll
+
+[Bochs.SoftwareSettings]
+AddReg = Bochs_SoftwareSettings
+
+[Bochs_SoftwareSettings]
+HKR,, InstalledDisplayDrivers, %REG_MULTI_SZ%, framebuf
+HKR,, VgaCompatible,           %REG_DWORD%,    0
+
+[Bochs.Services]
+AddService = bochsmp, 0x00000002, Bochs_Service
+
+[Bochs_Service]
+ServiceType   = 1
+StartType     = 3
+ErrorControl  = 0
+ServiceBinary = %12%\bochsmp.sys
+LoadOrderGroup = Video
+
+;-------------------------------- STRINGS -------------------------------
+
+[Strings]
+; Non-localizable
+ReactOS = "ReactOS Project"
+Bochs = "Bochs"
+
+REG_MULTI_SZ   = 0x00010000
+REG_DWORD      = 0x00010001
+
+; Localizable
+Bochs.DeviceDesc = "Bochs Graphics Adapter"
diff --git a/win32ss/drivers/miniport/bochs/bochsmp.rc 
b/win32ss/drivers/miniport/bochs/bochsmp.rc
new file mode 100644
index 00000000000..6524e2b64e8
--- /dev/null
+++ b/win32ss/drivers/miniport/bochs/bochsmp.rc
@@ -0,0 +1,5 @@
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION  "Bochs graphics adapter miniport"
+#define REACTOS_STR_INTERNAL_NAME     "bochsmp.sys"
+#define REACTOS_STR_ORIGINAL_FILENAME "bochsmp.sys"
+#include <reactos/version.rc>
diff --git a/win32ss/drivers/miniport/bochs/bochsmp_reg.inf 
b/win32ss/drivers/miniport/bochs/bochsmp_reg.inf
new file mode 100644
index 00000000000..740132606fb
--- /dev/null
+++ b/win32ss/drivers/miniport/bochs/bochsmp_reg.inf
@@ -0,0 +1,13 @@
+[AddReg]
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp","ErrorControl",0x00010001,0x00000000
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp","Group",0x00000000,"Video"
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp","ImagePath",0x00020000,"system32\drivers\bochsmp.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp","Start",0x00010001,0x00000003
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp","Type",0x00010001,0x00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp\Video","Service",0x00000000,"bochsmp"
+
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp\Device0","Device 
Description",0x00000000,"Bochs Graphics Adapter"
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp\Device0","InstalledDisplayDrivers",0x00010000,"framebuf"
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp\Device0","VgaCompatible",0x00010001,0
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp\Device0","DefaultSettings.XResolution",0x00010001,800
+HKLM,"SYSTEM\CurrentControlSet\Services\bochsmp\Device0","DefaultSettings.YResolution",0x00010001,600


Reply via email to