From 436ace9a904a964ad7487e5fa5ebe8168a09c40f Mon Sep 17 00:00:00 2001 From: John Davis Date: Mon, 17 Feb 2025 18:59:17 -0600 Subject: [PATCH] GraphicsBridge: Simplify graphics bridge PCI stub --- MacHyperVSupport.xcodeproj/project.pbxproj | 6 - .../GraphicsBridge/HyperVGraphicsBridge.cpp | 181 +++++++++--------- .../GraphicsBridge/HyperVGraphicsBridge.hpp | 14 +- .../HyperVGraphicsBridgePrivate.cpp | 33 ---- 4 files changed, 96 insertions(+), 138 deletions(-) delete mode 100644 MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridgePrivate.cpp diff --git a/MacHyperVSupport.xcodeproj/project.pbxproj b/MacHyperVSupport.xcodeproj/project.pbxproj index 2cf7f7c..bad2041 100644 --- a/MacHyperVSupport.xcodeproj/project.pbxproj +++ b/MacHyperVSupport.xcodeproj/project.pbxproj @@ -218,8 +218,6 @@ 41F2E43D2666E6A100CE26CE /* HyperVGraphicsBridge.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 41F2E43B2666E6A100CE26CE /* HyperVGraphicsBridge.hpp */; }; 41F2E45C26683B2C00CE26CE /* HyperVPCIRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F2E45A26683B2B00CE26CE /* HyperVPCIRoot.cpp */; }; 41F2E45D26683B2C00CE26CE /* HyperVPCIRoot.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 41F2E45B26683B2C00CE26CE /* HyperVPCIRoot.hpp */; }; - 41F47BE9290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */; }; - 41F47BEA290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */; }; 41F9B8F02849792200E0DCB2 /* HyperVPCIBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F9B8EE2849792200E0DCB2 /* HyperVPCIBridge.cpp */; }; 41F9B8F12849792200E0DCB2 /* HyperVPCIBridge.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 41F9B8EF2849792200E0DCB2 /* HyperVPCIBridge.hpp */; }; 41F9B8F8284983FF00E0DCB2 /* HyperVPCIBridgePrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F9B8F7284983FF00E0DCB2 /* HyperVPCIBridgePrivate.cpp */; }; @@ -656,7 +654,6 @@ 41F2E43B2666E6A100CE26CE /* HyperVGraphicsBridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HyperVGraphicsBridge.hpp; sourceTree = ""; }; 41F2E45A26683B2B00CE26CE /* HyperVPCIRoot.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVPCIRoot.cpp; sourceTree = ""; }; 41F2E45B26683B2C00CE26CE /* HyperVPCIRoot.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HyperVPCIRoot.hpp; sourceTree = ""; }; - 41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVGraphicsBridgePrivate.cpp; sourceTree = ""; }; 41F9B8EE2849792200E0DCB2 /* HyperVPCIBridge.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVPCIBridge.cpp; sourceTree = ""; }; 41F9B8EF2849792200E0DCB2 /* HyperVPCIBridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HyperVPCIBridge.hpp; sourceTree = ""; }; 41F9B8F7284983FF00E0DCB2 /* HyperVPCIBridgePrivate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVPCIBridgePrivate.cpp; sourceTree = ""; }; @@ -1142,7 +1139,6 @@ children = ( 41F2E43A2666E6A100CE26CE /* HyperVGraphicsBridge.cpp */, 41F2E43B2666E6A100CE26CE /* HyperVGraphicsBridge.hpp */, - 41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */, ); path = GraphicsBridge; sourceTree = ""; @@ -1854,7 +1850,6 @@ 4191F70C28F5057F00809232 /* HyperVFileCopyUserClient.cpp in Sources */, 417C576128C64B92003A177C /* HyperVVMBusInterrupts.cpp in Sources */, 416E418E2651E42E006DED6D /* HyperVMousePrivate.cpp in Sources */, - 41F47BE9290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */, 41AE1D0E289C95A9001A7B42 /* HyperVCPU.cpp in Sources */, 416E4180264A0D5D006DED6D /* HyperVStoragePrivate.cpp in Sources */, 41F2E43C2666E6A100CE26CE /* HyperVGraphicsBridge.cpp in Sources */, @@ -1904,7 +1899,6 @@ 4191F70D28F5057F00809232 /* HyperVFileCopyUserClient.cpp in Sources */, 417C576228C64B92003A177C /* HyperVVMBusInterrupts.cpp in Sources */, 41BF4615288CDF1200813670 /* HyperVMousePrivate.cpp in Sources */, - 41F47BEA290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */, 41AE1D0F289C95A9001A7B42 /* HyperVCPU.cpp in Sources */, 41BF4617288CDF1200813670 /* HyperVStoragePrivate.cpp in Sources */, 41BF4618288CDF1200813670 /* HyperVGraphicsBridge.cpp in Sources */, diff --git a/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.cpp b/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.cpp index 0a0a290..4c9b37d 100644 --- a/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.cpp +++ b/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.cpp @@ -2,18 +2,17 @@ // HyperVGraphicsBridge.cpp // Hyper-V synthetic graphics bridge // -// Copyright © 2021-2022 Goldfish64. All rights reserved. +// Copyright © 2021-2025 Goldfish64. All rights reserved. // #include "HyperVGraphicsBridge.hpp" #include "HyperVPCIRoot.hpp" -#include - OSDefineMetaClassAndStructors(HyperVGraphicsBridge, super); bool HyperVGraphicsBridge::start(IOService *provider) { - bool result = false; + PE_Video consoleInfo = { }; + HyperVPCIRoot *hvPCIRoot; IOReturn status; HVCheckDebugArgs(); @@ -25,80 +24,91 @@ bool HyperVGraphicsBridge::start(IOService *provider) { } // - // Locate root PCI bus instance. + // Pull console info. // - _hvPCIRoot = HyperVPCIRoot::getPCIRootInstance(); - if (_hvPCIRoot == nullptr) { + if (getPlatform()->getConsoleInfo(&consoleInfo) != kIOReturnSuccess) { + HVSYSLOG("Failed to get console info"); return false; } + HVDBGLOG("Console is at 0x%X (%ux%u, bpp: %u, bytes/row: %u)", + consoleInfo.v_baseAddr, consoleInfo.v_height, consoleInfo.v_width, consoleInfo.v_depth, consoleInfo.v_rowBytes); + _fbInitialBase = (UInt32)consoleInfo.v_baseAddr; + _fbInitialLength = (UInt32)(consoleInfo.v_height * consoleInfo.v_rowBytes); // - // Do not start on Gen1 VMs. + // Ensure parent is HyperVGraphics object. // - if (!_hvPCIRoot->isHyperVGen2()) { - HVDBGLOG("Not starting on Hyper-V Gen1 VM"); + if (OSDynamicCast(HyperVGraphics, provider) == nullptr) { + HVSYSLOG("Provider is not HyperVGraphics"); return false; } // - // Register with root PCI bridge. + // Locate root PCI bus instance. // - if (_hvPCIRoot->registerChildPCIBridge(this, &_pciBusNumber) != kIOReturnSuccess) { - HVSYSLOG("Failed to register with root PCI bus instance"); + hvPCIRoot = HyperVPCIRoot::getPCIRootInstance(); + if (hvPCIRoot == nullptr) { + HVSYSLOG("Failed to find root PCI bridge instance"); return false; } // - // Pull console info. - // TODO: Use actual info from Hyper-V VMBus device for this. + // Do not start on Gen1 VMs. // - if (getPlatform()->getConsoleInfo(&_consoleInfo) != kIOReturnSuccess) { - HVSYSLOG("Failed to get console info"); + if (!hvPCIRoot->isHyperVGen2()) { + HVDBGLOG("Not starting on Hyper-V Gen1 VM"); return false; } - HVDBGLOG("Console is at 0x%X (%ux%u, bpp: %u, bytes/row: %u)", - _consoleInfo.v_baseAddr, _consoleInfo.v_height, _consoleInfo.v_width, _consoleInfo.v_depth, _consoleInfo.v_rowBytes); + // + // Allocate PCI lock and register with root PCI bridge. + // _pciLock = IOSimpleLockAlloc(); - fillFakePCIDeviceSpace(); + if (_pciLock == nullptr) { + HVSYSLOG("Failed to allocate PCI lock"); + return false; + } - if (!super::start(provider)) { - HVSYSLOG("super::start() returned false"); + status = hvPCIRoot->registerChildPCIBridge(this, &_pciBusNumber); + if (status != kIOReturnSuccess) { + HVSYSLOG("Failed to register with root PCI bus instance"); + IOSimpleLockFree(_pciLock); return false; } // - // Add a friendly name to the child device produced. + // Fill PCI device config space. + // + // PCI bridge will contain a single PCI graphics device + // with the framebuffer memory at BAR0. The vendor/device ID is + // the same as what a generation 1 Hyper-V VM uses for the + // emulated graphics. // - OSIterator *childIterator = getChildIterator(gIOServicePlane); - if (childIterator != NULL) { - childIterator->reset(); - - IOService *childService = OSDynamicCast(IOService, childIterator->getNextObject()); - if (childService != NULL) { - HVDBGLOG("Found child %s", childService->getName()); - childService->setProperty("model", "Hyper-V Graphics"); - } + bzero(_fakePCIDeviceSpace, sizeof (_fakePCIDeviceSpace)); + OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigVendorID, kHyperVPCIVendorMicrosoft); + OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigDeviceID, kHyperVPCIDeviceHyperVVideo); + OSWriteLittleInt32(_fakePCIDeviceSpace, kIOPCIConfigRevisionID, 0x3000000); + OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigSubSystemVendorID, kHyperVPCIVendorMicrosoft); + OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigSubSystemID, kHyperVPCIDeviceHyperVVideo); + OSWriteLittleInt32(_fakePCIDeviceSpace, kIOPCIConfigBaseAddress0, (UInt32)_fbInitialBase); - childIterator->release(); + if (!super::start(provider)) { + HVSYSLOG("super::start() returned false"); + IOSimpleLockFree(_pciLock); + return false; } - do { - - - HVDBGLOG("Initialized Hyper-V Synthetic Graphics Bridge"); - result = true; - } while (false); - - if (!result) { - stop(provider); - } - return result; + HVDBGLOG("Initialized Hyper-V Synthetic Graphics Bridge"); + return true; } void HyperVGraphicsBridge::stop(IOService *provider) { HVDBGLOG("Hyper-V Synthetic Graphics Bridge is stopping"); + if (_pciLock != nullptr) { + IOSimpleLockFree(_pciLock); + } + super::stop(provider); } @@ -106,119 +116,108 @@ bool HyperVGraphicsBridge::configure(IOService *provider) { // // Add framebuffer memory range to bridge. // - UInt32 fbSize = (UInt32)(_consoleInfo.v_height * _consoleInfo.v_rowBytes); - addBridgeMemoryRange(_consoleInfo.v_baseAddr, fbSize, true); + HVDBGLOG("Adding framebuffer memory 0x%X length 0x%X to PCI bridge", _fbInitialBase, _fbInitialLength); + addBridgeMemoryRange(_fbInitialBase, _fbInitialLength, true); return super::configure(provider); } UInt32 HyperVGraphicsBridge::configRead32(IOPCIAddressSpace space, UInt8 offset) { - HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset); - UInt32 data; IOInterruptState ints; - + if (space.es.deviceNum != 0 || space.es.functionNum != 0) { return 0xFFFFFFFF; } - + ints = IOSimpleLockLockDisableInterrupt(_pciLock); data = OSReadLittleInt32(_fakePCIDeviceSpace, offset); - - if (offset == kIOPCIConfigurationOffsetBaseAddress0) { - HVDBGLOG("gonna read %X", data); - } - IOSimpleLockUnlockEnableInterrupt(_pciLock, ints); + + HVDBGLOG("Read 32-bit value %u from offset 0x%X", data, offset); return data; } void HyperVGraphicsBridge::configWrite32(IOPCIAddressSpace space, UInt8 offset, UInt32 data) { - HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset); - IOInterruptState ints; - if (space.es.deviceNum != 0 || space.es.functionNum != 0 || (offset > kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) || offset == kIOPCIConfigurationOffsetExpansionROMBase) { - HVDBGLOG("ignoring offset %X", offset); + if (space.es.deviceNum != 0 || space.es.functionNum != 0 + || (offset > kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) + || offset == kIOPCIConfigurationOffsetExpansionROMBase) { return; } - - if (offset == kIOPCIConfigurationOffsetBaseAddress0) { - HVDBGLOG("gonna write %X", data); - } - + HVDBGLOG("Writing 32-bit value %u to offset 0x%X", data, offset); + + // + // Return BAR0 size if requested. + // if (offset == kIOPCIConfigurationOffsetBaseAddress0 && data == 0xFFFFFFFF) { - HVDBGLOG("Got bar size request"); - UInt32 fbSize = (UInt32)(_consoleInfo.v_height * _consoleInfo.v_rowBytes); - OSWriteLittleInt32(_fakePCIDeviceSpace, offset, (0xFFFFFFFF - fbSize) + 1); + OSWriteLittleInt32(_fakePCIDeviceSpace, offset, (0xFFFFFFFF - _fbInitialLength) + 1); return; } - + ints = IOSimpleLockLockDisableInterrupt(_pciLock); OSWriteLittleInt32(_fakePCIDeviceSpace, offset, data); - IOSimpleLockUnlockEnableInterrupt(_pciLock, ints); } UInt16 HyperVGraphicsBridge::configRead16(IOPCIAddressSpace space, UInt8 offset) { - HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset); - UInt16 data; IOInterruptState ints; - + if (space.es.deviceNum != 0 || space.es.functionNum != 0) { return 0xFFFF; } - + ints = IOSimpleLockLockDisableInterrupt(_pciLock); data = OSReadLittleInt16(_fakePCIDeviceSpace, offset); - IOSimpleLockUnlockEnableInterrupt(_pciLock, ints); + + HVDBGLOG("Read 16-bit value %u from offset 0x%X", data, offset); return data; } void HyperVGraphicsBridge::configWrite16(IOPCIAddressSpace space, UInt8 offset, UInt16 data) { - HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset); - IOInterruptState ints; - - if (space.es.deviceNum != 0 || space.es.functionNum != 0 || (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) || offset == kIOPCIConfigurationOffsetExpansionROMBase) { + + if (space.es.deviceNum != 0 || space.es.functionNum != 0 + || (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) + || offset == kIOPCIConfigurationOffsetExpansionROMBase) { return; } - + HVDBGLOG("Writing 16-bit value %u to offset 0x%X", data, offset); + ints = IOSimpleLockLockDisableInterrupt(_pciLock); OSWriteLittleInt16(_fakePCIDeviceSpace, offset, data); - IOSimpleLockUnlockEnableInterrupt(_pciLock, ints); } UInt8 HyperVGraphicsBridge::configRead8(IOPCIAddressSpace space, UInt8 offset) { - HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset); - UInt8 data; IOInterruptState ints; - + if (space.es.deviceNum != 0 || space.es.functionNum != 0) { return 0xFF; } - + ints = IOSimpleLockLockDisableInterrupt(_pciLock); data = _fakePCIDeviceSpace[offset]; - IOSimpleLockUnlockEnableInterrupt(_pciLock, ints); + + HVDBGLOG("Read 8-bit value %u from offset 0x%X", data, offset); return data; } void HyperVGraphicsBridge::configWrite8(IOPCIAddressSpace space, UInt8 offset, UInt8 data) { - HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset); - IOInterruptState ints; - - if (space.es.deviceNum != 0 || space.es.functionNum != 0 || (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) || offset == kIOPCIConfigurationOffsetExpansionROMBase) { + + if (space.es.deviceNum != 0 || space.es.functionNum != 0 + || (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) + || offset == kIOPCIConfigurationOffsetExpansionROMBase) { return; } - + HVDBGLOG("Writing 8-bit value %u to offset 0x%X", data, offset); + ints = IOSimpleLockLockDisableInterrupt(_pciLock); _fakePCIDeviceSpace[offset] = data; - IOSimpleLockUnlockEnableInterrupt(_pciLock, ints); } diff --git a/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.hpp b/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.hpp index 589c55f..bd92ae4 100644 --- a/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.hpp +++ b/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.hpp @@ -2,15 +2,16 @@ // HyperVGraphicsBridge.hpp // Hyper-V synthetic graphics bridge // -// Copyright © 2021-2022 Goldfish64. All rights reserved. +// Copyright © 2021-2025 Goldfish64. All rights reserved. // #ifndef HyperVGraphicsBridge_hpp #define HyperVGraphicsBridge_hpp #include + #include "HyperVVMBusDevice.hpp" -#include "HyperVGraphicsRegs.hpp" +#include "HyperVGraphics.hpp" #include "HyperVPCIRoot.hpp" class HyperVGraphicsBridge : public HV_PCIBRIDGE_CLASS { @@ -19,18 +20,15 @@ class HyperVGraphicsBridge : public HV_PCIBRIDGE_CLASS { typedef HV_PCIBRIDGE_CLASS super; private: - HyperVPCIRoot *_hvPCIRoot = nullptr; - VMBusVersion _currentGraphicsVersion = { }; UInt8 _pciBusNumber = 0; // // Fake PCI structures. // - IOSimpleLock *_pciLock = nullptr; + IOSimpleLock *_pciLock = nullptr; UInt8 _fakePCIDeviceSpace[256]; - PE_Video _consoleInfo = { }; - - void fillFakePCIDeviceSpace(); + UInt32 _fbInitialBase = 0; + UInt32 _fbInitialLength = 0; public: // diff --git a/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridgePrivate.cpp b/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridgePrivate.cpp deleted file mode 100644 index 5b9591d..0000000 --- a/MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridgePrivate.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// HyperVGraphicsBridgePrivate.cpp -// Hyper-V synthetic graphics bridge -// -// Copyright © 2022 Goldfish64. All rights reserved. -// - -#include "HyperVGraphicsBridge.hpp" - -static const VMBusVersion graphicsVersions[] = { - kHyperVGraphicsVersionV3_2, - kHyperVGraphicsVersionV3_0 -}; - -void HyperVGraphicsBridge::fillFakePCIDeviceSpace() { - // - // Fill PCI device config space. - // - // PCI bridge will contain a single PCI graphics device - // with the framebuffer memory at BAR0. The vendor/device ID is - // the same as what a generation 1 Hyper-V VM uses for the - // emulated graphics. - // - bzero(_fakePCIDeviceSpace, sizeof (_fakePCIDeviceSpace)); - - OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigVendorID, kHyperVPCIVendorMicrosoft); - OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigDeviceID, kHyperVPCIDeviceHyperVVideo); - OSWriteLittleInt32(_fakePCIDeviceSpace, kIOPCIConfigRevisionID, 0x3000000); - OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigSubSystemVendorID, kHyperVPCIVendorMicrosoft); - OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigSubSystemID, kHyperVPCIDeviceHyperVVideo); - - OSWriteLittleInt32(_fakePCIDeviceSpace, kIOPCIConfigBaseAddress0, (UInt32)_consoleInfo.v_baseAddr); -}