Skip to content

Commit 436ace9

Browse files
committed
GraphicsBridge: Simplify graphics bridge PCI stub
1 parent 8ed533d commit 436ace9

File tree

4 files changed

+96
-138
lines changed

4 files changed

+96
-138
lines changed

MacHyperVSupport.xcodeproj/project.pbxproj

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,6 @@
218218
41F2E43D2666E6A100CE26CE /* HyperVGraphicsBridge.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 41F2E43B2666E6A100CE26CE /* HyperVGraphicsBridge.hpp */; };
219219
41F2E45C26683B2C00CE26CE /* HyperVPCIRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F2E45A26683B2B00CE26CE /* HyperVPCIRoot.cpp */; };
220220
41F2E45D26683B2C00CE26CE /* HyperVPCIRoot.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 41F2E45B26683B2C00CE26CE /* HyperVPCIRoot.hpp */; };
221-
41F47BE9290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */; };
222-
41F47BEA290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */; };
223221
41F9B8F02849792200E0DCB2 /* HyperVPCIBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F9B8EE2849792200E0DCB2 /* HyperVPCIBridge.cpp */; };
224222
41F9B8F12849792200E0DCB2 /* HyperVPCIBridge.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 41F9B8EF2849792200E0DCB2 /* HyperVPCIBridge.hpp */; };
225223
41F9B8F8284983FF00E0DCB2 /* HyperVPCIBridgePrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F9B8F7284983FF00E0DCB2 /* HyperVPCIBridgePrivate.cpp */; };
@@ -656,7 +654,6 @@
656654
41F2E43B2666E6A100CE26CE /* HyperVGraphicsBridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HyperVGraphicsBridge.hpp; sourceTree = "<group>"; };
657655
41F2E45A26683B2B00CE26CE /* HyperVPCIRoot.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVPCIRoot.cpp; sourceTree = "<group>"; };
658656
41F2E45B26683B2C00CE26CE /* HyperVPCIRoot.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HyperVPCIRoot.hpp; sourceTree = "<group>"; };
659-
41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVGraphicsBridgePrivate.cpp; sourceTree = "<group>"; };
660657
41F9B8EE2849792200E0DCB2 /* HyperVPCIBridge.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVPCIBridge.cpp; sourceTree = "<group>"; };
661658
41F9B8EF2849792200E0DCB2 /* HyperVPCIBridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HyperVPCIBridge.hpp; sourceTree = "<group>"; };
662659
41F9B8F7284983FF00E0DCB2 /* HyperVPCIBridgePrivate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HyperVPCIBridgePrivate.cpp; sourceTree = "<group>"; };
@@ -1142,7 +1139,6 @@
11421139
children = (
11431140
41F2E43A2666E6A100CE26CE /* HyperVGraphicsBridge.cpp */,
11441141
41F2E43B2666E6A100CE26CE /* HyperVGraphicsBridge.hpp */,
1145-
41F47BE8290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp */,
11461142
);
11471143
path = GraphicsBridge;
11481144
sourceTree = "<group>";
@@ -1854,7 +1850,6 @@
18541850
4191F70C28F5057F00809232 /* HyperVFileCopyUserClient.cpp in Sources */,
18551851
417C576128C64B92003A177C /* HyperVVMBusInterrupts.cpp in Sources */,
18561852
416E418E2651E42E006DED6D /* HyperVMousePrivate.cpp in Sources */,
1857-
41F47BE9290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */,
18581853
41AE1D0E289C95A9001A7B42 /* HyperVCPU.cpp in Sources */,
18591854
416E4180264A0D5D006DED6D /* HyperVStoragePrivate.cpp in Sources */,
18601855
41F2E43C2666E6A100CE26CE /* HyperVGraphicsBridge.cpp in Sources */,
@@ -1904,7 +1899,6 @@
19041899
4191F70D28F5057F00809232 /* HyperVFileCopyUserClient.cpp in Sources */,
19051900
417C576228C64B92003A177C /* HyperVVMBusInterrupts.cpp in Sources */,
19061901
41BF4615288CDF1200813670 /* HyperVMousePrivate.cpp in Sources */,
1907-
41F47BEA290EC06E00C0E3C5 /* HyperVGraphicsBridgePrivate.cpp in Sources */,
19081902
41AE1D0F289C95A9001A7B42 /* HyperVCPU.cpp in Sources */,
19091903
41BF4617288CDF1200813670 /* HyperVStoragePrivate.cpp in Sources */,
19101904
41BF4618288CDF1200813670 /* HyperVGraphicsBridge.cpp in Sources */,

MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.cpp

Lines changed: 90 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22
// HyperVGraphicsBridge.cpp
33
// Hyper-V synthetic graphics bridge
44
//
5-
// Copyright © 2021-2022 Goldfish64. All rights reserved.
5+
// Copyright © 2021-2025 Goldfish64. All rights reserved.
66
//
77

88
#include "HyperVGraphicsBridge.hpp"
99
#include "HyperVPCIRoot.hpp"
1010

11-
#include <IOKit/IOPlatformExpert.h>
12-
1311
OSDefineMetaClassAndStructors(HyperVGraphicsBridge, super);
1412

1513
bool HyperVGraphicsBridge::start(IOService *provider) {
16-
bool result = false;
14+
PE_Video consoleInfo = { };
15+
HyperVPCIRoot *hvPCIRoot;
1716
IOReturn status;
1817

1918
HVCheckDebugArgs();
@@ -25,200 +24,200 @@ bool HyperVGraphicsBridge::start(IOService *provider) {
2524
}
2625

2726
//
28-
// Locate root PCI bus instance.
27+
// Pull console info.
2928
//
30-
_hvPCIRoot = HyperVPCIRoot::getPCIRootInstance();
31-
if (_hvPCIRoot == nullptr) {
29+
if (getPlatform()->getConsoleInfo(&consoleInfo) != kIOReturnSuccess) {
30+
HVSYSLOG("Failed to get console info");
3231
return false;
3332
}
33+
HVDBGLOG("Console is at 0x%X (%ux%u, bpp: %u, bytes/row: %u)",
34+
consoleInfo.v_baseAddr, consoleInfo.v_height, consoleInfo.v_width, consoleInfo.v_depth, consoleInfo.v_rowBytes);
35+
_fbInitialBase = (UInt32)consoleInfo.v_baseAddr;
36+
_fbInitialLength = (UInt32)(consoleInfo.v_height * consoleInfo.v_rowBytes);
3437

3538
//
36-
// Do not start on Gen1 VMs.
39+
// Ensure parent is HyperVGraphics object.
3740
//
38-
if (!_hvPCIRoot->isHyperVGen2()) {
39-
HVDBGLOG("Not starting on Hyper-V Gen1 VM");
41+
if (OSDynamicCast(HyperVGraphics, provider) == nullptr) {
42+
HVSYSLOG("Provider is not HyperVGraphics");
4043
return false;
4144
}
4245

4346
//
44-
// Register with root PCI bridge.
47+
// Locate root PCI bus instance.
4548
//
46-
if (_hvPCIRoot->registerChildPCIBridge(this, &_pciBusNumber) != kIOReturnSuccess) {
47-
HVSYSLOG("Failed to register with root PCI bus instance");
49+
hvPCIRoot = HyperVPCIRoot::getPCIRootInstance();
50+
if (hvPCIRoot == nullptr) {
51+
HVSYSLOG("Failed to find root PCI bridge instance");
4852
return false;
4953
}
5054

5155
//
52-
// Pull console info.
53-
// TODO: Use actual info from Hyper-V VMBus device for this.
56+
// Do not start on Gen1 VMs.
5457
//
55-
if (getPlatform()->getConsoleInfo(&_consoleInfo) != kIOReturnSuccess) {
56-
HVSYSLOG("Failed to get console info");
58+
if (!hvPCIRoot->isHyperVGen2()) {
59+
HVDBGLOG("Not starting on Hyper-V Gen1 VM");
5760
return false;
5861
}
59-
HVDBGLOG("Console is at 0x%X (%ux%u, bpp: %u, bytes/row: %u)",
60-
_consoleInfo.v_baseAddr, _consoleInfo.v_height, _consoleInfo.v_width, _consoleInfo.v_depth, _consoleInfo.v_rowBytes);
6162

63+
//
64+
// Allocate PCI lock and register with root PCI bridge.
65+
//
6266
_pciLock = IOSimpleLockAlloc();
63-
fillFakePCIDeviceSpace();
67+
if (_pciLock == nullptr) {
68+
HVSYSLOG("Failed to allocate PCI lock");
69+
return false;
70+
}
6471

65-
if (!super::start(provider)) {
66-
HVSYSLOG("super::start() returned false");
72+
status = hvPCIRoot->registerChildPCIBridge(this, &_pciBusNumber);
73+
if (status != kIOReturnSuccess) {
74+
HVSYSLOG("Failed to register with root PCI bus instance");
75+
IOSimpleLockFree(_pciLock);
6776
return false;
6877
}
6978

7079
//
71-
// Add a friendly name to the child device produced.
80+
// Fill PCI device config space.
81+
//
82+
// PCI bridge will contain a single PCI graphics device
83+
// with the framebuffer memory at BAR0. The vendor/device ID is
84+
// the same as what a generation 1 Hyper-V VM uses for the
85+
// emulated graphics.
7286
//
73-
OSIterator *childIterator = getChildIterator(gIOServicePlane);
74-
if (childIterator != NULL) {
75-
childIterator->reset();
76-
77-
IOService *childService = OSDynamicCast(IOService, childIterator->getNextObject());
78-
if (childService != NULL) {
79-
HVDBGLOG("Found child %s", childService->getName());
80-
childService->setProperty("model", "Hyper-V Graphics");
81-
}
87+
bzero(_fakePCIDeviceSpace, sizeof (_fakePCIDeviceSpace));
88+
OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigVendorID, kHyperVPCIVendorMicrosoft);
89+
OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigDeviceID, kHyperVPCIDeviceHyperVVideo);
90+
OSWriteLittleInt32(_fakePCIDeviceSpace, kIOPCIConfigRevisionID, 0x3000000);
91+
OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigSubSystemVendorID, kHyperVPCIVendorMicrosoft);
92+
OSWriteLittleInt16(_fakePCIDeviceSpace, kIOPCIConfigSubSystemID, kHyperVPCIDeviceHyperVVideo);
93+
OSWriteLittleInt32(_fakePCIDeviceSpace, kIOPCIConfigBaseAddress0, (UInt32)_fbInitialBase);
8294

83-
childIterator->release();
95+
if (!super::start(provider)) {
96+
HVSYSLOG("super::start() returned false");
97+
IOSimpleLockFree(_pciLock);
98+
return false;
8499
}
85100

86-
do {
87-
88-
89-
HVDBGLOG("Initialized Hyper-V Synthetic Graphics Bridge");
90-
result = true;
91-
} while (false);
92-
93-
if (!result) {
94-
stop(provider);
95-
}
96-
return result;
101+
HVDBGLOG("Initialized Hyper-V Synthetic Graphics Bridge");
102+
return true;
97103
}
98104

99105
void HyperVGraphicsBridge::stop(IOService *provider) {
100106
HVDBGLOG("Hyper-V Synthetic Graphics Bridge is stopping");
101107

108+
if (_pciLock != nullptr) {
109+
IOSimpleLockFree(_pciLock);
110+
}
111+
102112
super::stop(provider);
103113
}
104114

105115
bool HyperVGraphicsBridge::configure(IOService *provider) {
106116
//
107117
// Add framebuffer memory range to bridge.
108118
//
109-
UInt32 fbSize = (UInt32)(_consoleInfo.v_height * _consoleInfo.v_rowBytes);
110-
addBridgeMemoryRange(_consoleInfo.v_baseAddr, fbSize, true);
119+
HVDBGLOG("Adding framebuffer memory 0x%X length 0x%X to PCI bridge", _fbInitialBase, _fbInitialLength);
120+
addBridgeMemoryRange(_fbInitialBase, _fbInitialLength, true);
111121
return super::configure(provider);
112122
}
113123

114124
UInt32 HyperVGraphicsBridge::configRead32(IOPCIAddressSpace space, UInt8 offset) {
115-
HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset);
116-
117125
UInt32 data;
118126
IOInterruptState ints;
119-
127+
120128
if (space.es.deviceNum != 0 || space.es.functionNum != 0) {
121129
return 0xFFFFFFFF;
122130
}
123-
131+
124132
ints = IOSimpleLockLockDisableInterrupt(_pciLock);
125133
data = OSReadLittleInt32(_fakePCIDeviceSpace, offset);
126-
127-
if (offset == kIOPCIConfigurationOffsetBaseAddress0) {
128-
HVDBGLOG("gonna read %X", data);
129-
}
130-
131134
IOSimpleLockUnlockEnableInterrupt(_pciLock, ints);
135+
136+
HVDBGLOG("Read 32-bit value %u from offset 0x%X", data, offset);
132137
return data;
133138
}
134139

135140
void HyperVGraphicsBridge::configWrite32(IOPCIAddressSpace space, UInt8 offset, UInt32 data) {
136-
HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset);
137-
138141
IOInterruptState ints;
139142

140-
if (space.es.deviceNum != 0 || space.es.functionNum != 0 || (offset > kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) || offset == kIOPCIConfigurationOffsetExpansionROMBase) {
141-
HVDBGLOG("ignoring offset %X", offset);
143+
if (space.es.deviceNum != 0 || space.es.functionNum != 0
144+
|| (offset > kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5)
145+
|| offset == kIOPCIConfigurationOffsetExpansionROMBase) {
142146
return;
143147
}
144-
145-
if (offset == kIOPCIConfigurationOffsetBaseAddress0) {
146-
HVDBGLOG("gonna write %X", data);
147-
}
148-
148+
HVDBGLOG("Writing 32-bit value %u to offset 0x%X", data, offset);
149+
150+
//
151+
// Return BAR0 size if requested.
152+
//
149153
if (offset == kIOPCIConfigurationOffsetBaseAddress0 && data == 0xFFFFFFFF) {
150-
HVDBGLOG("Got bar size request");
151-
UInt32 fbSize = (UInt32)(_consoleInfo.v_height * _consoleInfo.v_rowBytes);
152-
OSWriteLittleInt32(_fakePCIDeviceSpace, offset, (0xFFFFFFFF - fbSize) + 1);
154+
OSWriteLittleInt32(_fakePCIDeviceSpace, offset, (0xFFFFFFFF - _fbInitialLength) + 1);
153155
return;
154156
}
155-
157+
156158
ints = IOSimpleLockLockDisableInterrupt(_pciLock);
157159
OSWriteLittleInt32(_fakePCIDeviceSpace, offset, data);
158-
159160
IOSimpleLockUnlockEnableInterrupt(_pciLock, ints);
160161
}
161162

162163
UInt16 HyperVGraphicsBridge::configRead16(IOPCIAddressSpace space, UInt8 offset) {
163-
HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset);
164-
165164
UInt16 data;
166165
IOInterruptState ints;
167-
166+
168167
if (space.es.deviceNum != 0 || space.es.functionNum != 0) {
169168
return 0xFFFF;
170169
}
171-
170+
172171
ints = IOSimpleLockLockDisableInterrupt(_pciLock);
173172
data = OSReadLittleInt16(_fakePCIDeviceSpace, offset);
174-
175173
IOSimpleLockUnlockEnableInterrupt(_pciLock, ints);
174+
175+
HVDBGLOG("Read 16-bit value %u from offset 0x%X", data, offset);
176176
return data;
177177
}
178178

179179
void HyperVGraphicsBridge::configWrite16(IOPCIAddressSpace space, UInt8 offset, UInt16 data) {
180-
HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset);
181-
182180
IOInterruptState ints;
183-
184-
if (space.es.deviceNum != 0 || space.es.functionNum != 0 || (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) || offset == kIOPCIConfigurationOffsetExpansionROMBase) {
181+
182+
if (space.es.deviceNum != 0 || space.es.functionNum != 0
183+
|| (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5)
184+
|| offset == kIOPCIConfigurationOffsetExpansionROMBase) {
185185
return;
186186
}
187-
187+
HVDBGLOG("Writing 16-bit value %u to offset 0x%X", data, offset);
188+
188189
ints = IOSimpleLockLockDisableInterrupt(_pciLock);
189190
OSWriteLittleInt16(_fakePCIDeviceSpace, offset, data);
190-
191191
IOSimpleLockUnlockEnableInterrupt(_pciLock, ints);
192192
}
193193

194194
UInt8 HyperVGraphicsBridge::configRead8(IOPCIAddressSpace space, UInt8 offset) {
195-
HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset);
196-
197195
UInt8 data;
198196
IOInterruptState ints;
199-
197+
200198
if (space.es.deviceNum != 0 || space.es.functionNum != 0) {
201199
return 0xFF;
202200
}
203-
201+
204202
ints = IOSimpleLockLockDisableInterrupt(_pciLock);
205203
data = _fakePCIDeviceSpace[offset];
206-
207204
IOSimpleLockUnlockEnableInterrupt(_pciLock, ints);
205+
206+
HVDBGLOG("Read 8-bit value %u from offset 0x%X", data, offset);
208207
return data;
209208
}
210209

211210
void HyperVGraphicsBridge::configWrite8(IOPCIAddressSpace space, UInt8 offset, UInt8 data) {
212-
HVDBGLOG("Bus: %u, device: %u, function: %u, offset %X", space.es.busNum, space.es.deviceNum, space.es.functionNum, offset);
213-
214211
IOInterruptState ints;
215-
216-
if (space.es.deviceNum != 0 || space.es.functionNum != 0 || (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5) || offset == kIOPCIConfigurationOffsetExpansionROMBase) {
212+
213+
if (space.es.deviceNum != 0 || space.es.functionNum != 0
214+
|| (offset >= kIOPCIConfigurationOffsetBaseAddress0 && offset <= kIOPCIConfigurationOffsetBaseAddress5)
215+
|| offset == kIOPCIConfigurationOffsetExpansionROMBase) {
217216
return;
218217
}
219-
218+
HVDBGLOG("Writing 8-bit value %u to offset 0x%X", data, offset);
219+
220220
ints = IOSimpleLockLockDisableInterrupt(_pciLock);
221221
_fakePCIDeviceSpace[offset] = data;
222-
223222
IOSimpleLockUnlockEnableInterrupt(_pciLock, ints);
224223
}

MacHyperVSupport/GraphicsBridge/HyperVGraphicsBridge.hpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
// HyperVGraphicsBridge.hpp
33
// Hyper-V synthetic graphics bridge
44
//
5-
// Copyright © 2021-2022 Goldfish64. All rights reserved.
5+
// Copyright © 2021-2025 Goldfish64. All rights reserved.
66
//
77

88
#ifndef HyperVGraphicsBridge_hpp
99
#define HyperVGraphicsBridge_hpp
1010

1111
#include <IOKit/pci/IOPCIBridge.h>
12+
1213
#include "HyperVVMBusDevice.hpp"
13-
#include "HyperVGraphicsRegs.hpp"
14+
#include "HyperVGraphics.hpp"
1415
#include "HyperVPCIRoot.hpp"
1516

1617
class HyperVGraphicsBridge : public HV_PCIBRIDGE_CLASS {
@@ -19,18 +20,15 @@ class HyperVGraphicsBridge : public HV_PCIBRIDGE_CLASS {
1920
typedef HV_PCIBRIDGE_CLASS super;
2021

2122
private:
22-
HyperVPCIRoot *_hvPCIRoot = nullptr;
23-
VMBusVersion _currentGraphicsVersion = { };
2423
UInt8 _pciBusNumber = 0;
2524

2625
//
2726
// Fake PCI structures.
2827
//
29-
IOSimpleLock *_pciLock = nullptr;
28+
IOSimpleLock *_pciLock = nullptr;
3029
UInt8 _fakePCIDeviceSpace[256];
31-
PE_Video _consoleInfo = { };
32-
33-
void fillFakePCIDeviceSpace();
30+
UInt32 _fbInitialBase = 0;
31+
UInt32 _fbInitialLength = 0;
3432

3533
public:
3634
//

0 commit comments

Comments
 (0)