https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a33719500c71638da03e83...
commit a33719500c71638da03e83e0c9914ec9c9fe3c27 Author: Hervé Poussineau hpoussin@reactos.org AuthorDate: Mon Oct 17 12:00:00 2022 +0200 Commit: hpoussin 32227662+hpoussin@users.noreply.github.com 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 hpoussin@reactos.org + */ + +#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 hpoussin@reactos.org + */ + +#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