├── .gitignore ├── .gitmodules ├── LICENSE.md ├── MacVFN.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── MacVFN ├── Info.plist ├── MacVFN.cpp ├── MacVFN.entitlements ├── MacVFN.iig ├── MacVFNBuffers.h ├── MacVFNShared.h ├── MacVFNUserClient.cpp └── MacVFNUserClient.iig ├── MacVFNInstaller ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ └── MainMenu.xib ├── MacVFNInstaller.entitlements └── main.m ├── Makefile └── README.MD /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata/ 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "MacVFN/libvfn"] 2 | path = MacVFN/libvfn 3 | url = https://github.com/Baekalfen/libvfn 4 | branch = driverkit 5 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Mads Ynddal 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /MacVFN.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 090B2FBC2B10D3420079CDF8 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 090B2F902B10D3420079CDF8 /* util.c */; }; 11 | 090B2FBD2B10D3420079CDF8 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = 090B2F912B10D3420079CDF8 /* types.h */; }; 12 | 090B2FBE2B10D3420079CDF8 /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = 090B2F922B10D3420079CDF8 /* queue.c */; }; 13 | 090B2FBF2B10D3420079CDF8 /* rq.c in Sources */ = {isa = PBXBuildFile; fileRef = 090B2F932B10D3420079CDF8 /* rq.c */; }; 14 | 090B2FC12B10D3420079CDF8 /* core.c in Sources */ = {isa = PBXBuildFile; fileRef = 090B2F952B10D3420079CDF8 /* core.c */; }; 15 | 090B2FD12B10D3420079CDF8 /* mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 090B2FAA2B10D3420079CDF8 /* mem.c */; }; 16 | 090B2FDA2B10D3420079CDF8 /* pci.c in Sources */ = {isa = PBXBuildFile; fileRef = 090B2FB72B10D3420079CDF8 /* pci.c */; }; 17 | 0922B0512B10CCC1009CC5FF /* DriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0922B0502B10CCC1009CC5FF /* DriverKit.framework */; }; 18 | 0922B0542B10CCC1009CC5FF /* MacVFN.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0922B0532B10CCC1009CC5FF /* MacVFN.cpp */; }; 19 | 0922B0562B10CCC1009CC5FF /* MacVFN.iig in Sources */ = {isa = PBXBuildFile; fileRef = 0922B0552B10CCC1009CC5FF /* MacVFN.iig */; }; 20 | 0922B0692B10CE53009CC5FF /* PCIDriverKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0922B0652B10CE46009CC5FF /* PCIDriverKit.framework */; }; 21 | 0922B06A2B10CE53009CC5FF /* PCIDriverKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0922B0652B10CE46009CC5FF /* PCIDriverKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | 0942632F2BC0106D0038C603 /* context.c in Sources */ = {isa = PBXBuildFile; fileRef = 0942632E2BC0106D0038C603 /* context.c */; }; 23 | 095CB91C2B10F22900EA2A98 /* MacVFNUserClient.iig in Sources */ = {isa = PBXBuildFile; fileRef = 095CB91B2B10F22900EA2A98 /* MacVFNUserClient.iig */; }; 24 | 095CB91E2B10F24500EA2A98 /* MacVFNUserClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 095CB91D2B10F24500EA2A98 /* MacVFNUserClient.cpp */; }; 25 | 099C79882BBFEA1A00CD1F29 /* skiplist.c in Sources */ = {isa = PBXBuildFile; fileRef = 099C79832BBFEA1A00CD1F29 /* skiplist.c */; }; 26 | 099C798E2BBFF15000CD1F29 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 099C798B2BBFF15000CD1F29 /* util.c */; }; 27 | 09DC13982BB196F900EBDE37 /* dma.c in Sources */ = {isa = PBXBuildFile; fileRef = 09DC13902BB196F900EBDE37 /* dma.c */; }; 28 | 09DC13992BB196F900EBDE37 /* driverkit.c in Sources */ = {isa = PBXBuildFile; fileRef = 09DC13912BB196F900EBDE37 /* driverkit.c */; }; 29 | 09DE90572BC7DB9D0035961E /* ticks.c in Sources */ = {isa = PBXBuildFile; fileRef = 09DE90562BC7DB9D0035961E /* ticks.c */; }; 30 | 09DE905D2BC7DCE30035961E /* rdtsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 09DE90592BC7DCE20035961E /* rdtsc.c */; }; 31 | 09F93E532B10E115004694A2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 09F93E522B10E115004694A2 /* AppDelegate.m */; }; 32 | 09F93E552B10E116004694A2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 09F93E542B10E116004694A2 /* Assets.xcassets */; }; 33 | 09F93E582B10E116004694A2 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 09F93E562B10E116004694A2 /* MainMenu.xib */; }; 34 | 09F93E5A2B10E116004694A2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 09F93E592B10E116004694A2 /* main.m */; }; 35 | 09F93E612B10E3E5004694A2 /* com.openmpdk.MacVFN.dext in Embed System Extensions */ = {isa = PBXBuildFile; fileRef = 0922B04D2B10CCC1009CC5FF /* com.openmpdk.MacVFN.dext */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXContainerItemProxy section */ 39 | 09F93E5F2B10E11B004694A2 /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = 0922B0442B10CCC1009CC5FF /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = 0922B04C2B10CCC1009CC5FF; 44 | remoteInfo = MacVFN; 45 | }; 46 | 09F93E622B10E3E5004694A2 /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = 0922B0442B10CCC1009CC5FF /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = 0922B04C2B10CCC1009CC5FF; 51 | remoteInfo = MacVFN; 52 | }; 53 | /* End PBXContainerItemProxy section */ 54 | 55 | /* Begin PBXCopyFilesBuildPhase section */ 56 | 0922B06B2B10CE53009CC5FF /* Embed Frameworks */ = { 57 | isa = PBXCopyFilesBuildPhase; 58 | buildActionMask = 2147483647; 59 | dstPath = ""; 60 | dstSubfolderSpec = 10; 61 | files = ( 62 | 0922B06A2B10CE53009CC5FF /* PCIDriverKit.framework in Embed Frameworks */, 63 | ); 64 | name = "Embed Frameworks"; 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | 09F93E642B10E3E5004694A2 /* Embed System Extensions */ = { 68 | isa = PBXCopyFilesBuildPhase; 69 | buildActionMask = 2147483647; 70 | dstPath = "$(SYSTEM_EXTENSIONS_FOLDER_PATH)"; 71 | dstSubfolderSpec = 16; 72 | files = ( 73 | 09F93E612B10E3E5004694A2 /* com.openmpdk.MacVFN.dext in Embed System Extensions */, 74 | ); 75 | name = "Embed System Extensions"; 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXCopyFilesBuildPhase section */ 79 | 80 | /* Begin PBXFileReference section */ 81 | 090B2F902B10D3420079CDF8 /* util.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = util.c; sourceTree = ""; }; 82 | 090B2F912B10D3420079CDF8 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; 83 | 090B2F922B10D3420079CDF8 /* queue.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = queue.c; sourceTree = ""; }; 84 | 090B2F932B10D3420079CDF8 /* rq.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = rq.c; sourceTree = ""; }; 85 | 090B2F952B10D3420079CDF8 /* core.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = core.c; sourceTree = ""; }; 86 | 090B2FAA2B10D3420079CDF8 /* mem.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = mem.c; sourceTree = ""; }; 87 | 090B2FB72B10D3420079CDF8 /* pci.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = pci.c; sourceTree = ""; }; 88 | 0922B04D2B10CCC1009CC5FF /* com.openmpdk.MacVFN.dext */ = {isa = PBXFileReference; explicitFileType = "wrapper.driver-extension"; includeInIndex = 0; path = com.openmpdk.MacVFN.dext; sourceTree = BUILT_PRODUCTS_DIR; }; 89 | 0922B0502B10CCC1009CC5FF /* DriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DriverKit.framework; path = Library/Frameworks/DriverKit.framework; sourceTree = DEVELOPER_DIR; }; 90 | 0922B0532B10CCC1009CC5FF /* MacVFN.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MacVFN.cpp; sourceTree = ""; }; 91 | 0922B0552B10CCC1009CC5FF /* MacVFN.iig */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.iig; path = MacVFN.iig; sourceTree = ""; }; 92 | 0922B0572B10CCC1009CC5FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 93 | 0922B05E2B10CE46009CC5FF /* HIDDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = HIDDriverKit.framework; sourceTree = ""; }; 94 | 0922B05F2B10CE46009CC5FF /* SCSIPeripheralsDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SCSIPeripheralsDriverKit.framework; sourceTree = ""; }; 95 | 0922B0602B10CE46009CC5FF /* DriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = DriverKit.framework; sourceTree = ""; }; 96 | 0922B0612B10CE46009CC5FF /* BlockStorageDeviceDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = BlockStorageDeviceDriverKit.framework; sourceTree = ""; }; 97 | 0922B0622B10CE46009CC5FF /* SerialDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SerialDriverKit.framework; sourceTree = ""; }; 98 | 0922B0632B10CE46009CC5FF /* NetworkingDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = NetworkingDriverKit.framework; sourceTree = ""; }; 99 | 0922B0642B10CE46009CC5FF /* AudioDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AudioDriverKit.framework; sourceTree = ""; }; 100 | 0922B0652B10CE46009CC5FF /* PCIDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = PCIDriverKit.framework; sourceTree = ""; }; 101 | 0922B0662B10CE46009CC5FF /* USBSerialDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = USBSerialDriverKit.framework; sourceTree = ""; }; 102 | 0922B0672B10CE46009CC5FF /* SCSIControllerDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SCSIControllerDriverKit.framework; sourceTree = ""; }; 103 | 0922B0682B10CE46009CC5FF /* USBDriverKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = USBDriverKit.framework; sourceTree = ""; }; 104 | 0942632E2BC0106D0038C603 /* context.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = context.c; sourceTree = ""; }; 105 | 095CB91B2B10F22900EA2A98 /* MacVFNUserClient.iig */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.iig; path = MacVFNUserClient.iig; sourceTree = ""; }; 106 | 095CB91D2B10F24500EA2A98 /* MacVFNUserClient.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MacVFNUserClient.cpp; sourceTree = ""; }; 107 | 095CB9202B10F2BB00EA2A98 /* MacVFNShared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MacVFNShared.h; sourceTree = ""; }; 108 | 099C79832BBFEA1A00CD1F29 /* skiplist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = skiplist.c; sourceTree = ""; }; 109 | 099C798B2BBFF15000CD1F29 /* util.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = util.c; sourceTree = ""; }; 110 | 09DC13902BB196F900EBDE37 /* dma.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = dma.c; sourceTree = ""; }; 111 | 09DC13912BB196F900EBDE37 /* driverkit.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = driverkit.c; sourceTree = ""; }; 112 | 09DE90562BC7DB9D0035961E /* ticks.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = ticks.c; sourceTree = ""; }; 113 | 09DE90592BC7DCE20035961E /* rdtsc.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = rdtsc.c; sourceTree = ""; }; 114 | 09F93E4F2B10E115004694A2 /* MacVFNInstaller.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacVFNInstaller.app; sourceTree = BUILT_PRODUCTS_DIR; }; 115 | 09F93E512B10E115004694A2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 116 | 09F93E522B10E115004694A2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 117 | 09F93E542B10E116004694A2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 118 | 09F93E572B10E116004694A2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 119 | 09F93E592B10E116004694A2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 120 | 09F93E5B2B10E116004694A2 /* MacVFNInstaller.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MacVFNInstaller.entitlements; sourceTree = ""; }; 121 | /* End PBXFileReference section */ 122 | 123 | /* Begin PBXFrameworksBuildPhase section */ 124 | 0922B04A2B10CCC1009CC5FF /* Frameworks */ = { 125 | isa = PBXFrameworksBuildPhase; 126 | buildActionMask = 2147483647; 127 | files = ( 128 | 0922B0692B10CE53009CC5FF /* PCIDriverKit.framework in Frameworks */, 129 | 0922B0512B10CCC1009CC5FF /* DriverKit.framework in Frameworks */, 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | 09F93E4C2B10E115004694A2 /* Frameworks */ = { 134 | isa = PBXFrameworksBuildPhase; 135 | buildActionMask = 2147483647; 136 | files = ( 137 | ); 138 | runOnlyForDeploymentPostprocessing = 0; 139 | }; 140 | /* End PBXFrameworksBuildPhase section */ 141 | 142 | /* Begin PBXGroup section */ 143 | 090B2F892B10D32E0079CDF8 /* libvfn */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 090B2F8A2B10D3420079CDF8 /* src */, 147 | ); 148 | path = libvfn; 149 | sourceTree = ""; 150 | }; 151 | 090B2F8A2B10D3420079CDF8 /* src */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 099C798C2BBFF15000CD1F29 /* pci */, 155 | 099C79852BBFEA1A00CD1F29 /* util */, 156 | 09DC13952BB196F900EBDE37 /* iommu */, 157 | 090B2F8F2B10D3420079CDF8 /* nvme */, 158 | 090B2FA42B10D3420079CDF8 /* support */, 159 | 090B2FB52B10D3420079CDF8 /* driverkit */, 160 | ); 161 | path = src; 162 | sourceTree = ""; 163 | }; 164 | 090B2F8F2B10D3420079CDF8 /* nvme */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 090B2F902B10D3420079CDF8 /* util.c */, 168 | 090B2F912B10D3420079CDF8 /* types.h */, 169 | 090B2F922B10D3420079CDF8 /* queue.c */, 170 | 090B2F932B10D3420079CDF8 /* rq.c */, 171 | 090B2F952B10D3420079CDF8 /* core.c */, 172 | ); 173 | path = nvme; 174 | sourceTree = ""; 175 | }; 176 | 090B2FA42B10D3420079CDF8 /* support */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 09DE905B2BC7DCE20035961E /* arch */, 180 | 09DE90562BC7DB9D0035961E /* ticks.c */, 181 | 090B2FA82B10D3420079CDF8 /* platform */, 182 | ); 183 | path = support; 184 | sourceTree = ""; 185 | }; 186 | 090B2FA82B10D3420079CDF8 /* platform */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 090B2FA92B10D3420079CDF8 /* macos */, 190 | ); 191 | path = platform; 192 | sourceTree = ""; 193 | }; 194 | 090B2FA92B10D3420079CDF8 /* macos */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | 090B2FAA2B10D3420079CDF8 /* mem.c */, 198 | ); 199 | path = macos; 200 | sourceTree = ""; 201 | }; 202 | 090B2FB52B10D3420079CDF8 /* driverkit */ = { 203 | isa = PBXGroup; 204 | children = ( 205 | 090B2FB72B10D3420079CDF8 /* pci.c */, 206 | ); 207 | path = driverkit; 208 | sourceTree = ""; 209 | }; 210 | 0922B0432B10CCC1009CC5FF = { 211 | isa = PBXGroup; 212 | children = ( 213 | 0922B0522B10CCC1009CC5FF /* MacVFN */, 214 | 09F93E502B10E115004694A2 /* MacVFNInstaller */, 215 | 0922B04F2B10CCC1009CC5FF /* Frameworks */, 216 | 0922B04E2B10CCC1009CC5FF /* Products */, 217 | ); 218 | sourceTree = ""; 219 | }; 220 | 0922B04E2B10CCC1009CC5FF /* Products */ = { 221 | isa = PBXGroup; 222 | children = ( 223 | 0922B04D2B10CCC1009CC5FF /* com.openmpdk.MacVFN.dext */, 224 | 09F93E4F2B10E115004694A2 /* MacVFNInstaller.app */, 225 | ); 226 | name = Products; 227 | sourceTree = ""; 228 | }; 229 | 0922B04F2B10CCC1009CC5FF /* Frameworks */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | 0922B05D2B10CE46009CC5FF /* Frameworks */, 233 | 0922B0502B10CCC1009CC5FF /* DriverKit.framework */, 234 | ); 235 | name = Frameworks; 236 | sourceTree = ""; 237 | }; 238 | 0922B0522B10CCC1009CC5FF /* MacVFN */ = { 239 | isa = PBXGroup; 240 | children = ( 241 | 09323B9F2BC6DB2C0009693A /* ccan */, 242 | 090B2F892B10D32E0079CDF8 /* libvfn */, 243 | 0922B0532B10CCC1009CC5FF /* MacVFN.cpp */, 244 | 0922B0552B10CCC1009CC5FF /* MacVFN.iig */, 245 | 095CB9202B10F2BB00EA2A98 /* MacVFNShared.h */, 246 | 0922B0572B10CCC1009CC5FF /* Info.plist */, 247 | 095CB91B2B10F22900EA2A98 /* MacVFNUserClient.iig */, 248 | 095CB91D2B10F24500EA2A98 /* MacVFNUserClient.cpp */, 249 | ); 250 | path = MacVFN; 251 | sourceTree = ""; 252 | }; 253 | 0922B05D2B10CE46009CC5FF /* Frameworks */ = { 254 | isa = PBXGroup; 255 | children = ( 256 | 0922B05E2B10CE46009CC5FF /* HIDDriverKit.framework */, 257 | 0922B05F2B10CE46009CC5FF /* SCSIPeripheralsDriverKit.framework */, 258 | 0922B0602B10CE46009CC5FF /* DriverKit.framework */, 259 | 0922B0612B10CE46009CC5FF /* BlockStorageDeviceDriverKit.framework */, 260 | 0922B0622B10CE46009CC5FF /* SerialDriverKit.framework */, 261 | 0922B0632B10CE46009CC5FF /* NetworkingDriverKit.framework */, 262 | 0922B0642B10CE46009CC5FF /* AudioDriverKit.framework */, 263 | 0922B0652B10CE46009CC5FF /* PCIDriverKit.framework */, 264 | 0922B0662B10CE46009CC5FF /* USBSerialDriverKit.framework */, 265 | 0922B0672B10CE46009CC5FF /* SCSIControllerDriverKit.framework */, 266 | 0922B0682B10CE46009CC5FF /* USBDriverKit.framework */, 267 | ); 268 | name = Frameworks; 269 | path = Platforms/DriverKit.platform/Developer/SDKs/DriverKit.sdk/System/DriverKit/System/Library/Frameworks; 270 | sourceTree = DEVELOPER_DIR; 271 | }; 272 | 09323B982BC6DB2C0009693A /* ccan */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | ); 276 | path = ccan; 277 | sourceTree = ""; 278 | }; 279 | 09323B9F2BC6DB2C0009693A /* ccan */ = { 280 | isa = PBXGroup; 281 | children = ( 282 | 09323B982BC6DB2C0009693A /* ccan */, 283 | ); 284 | name = ccan; 285 | path = libvfn/ccan; 286 | sourceTree = ""; 287 | }; 288 | 099C79852BBFEA1A00CD1F29 /* util */ = { 289 | isa = PBXGroup; 290 | children = ( 291 | 099C79832BBFEA1A00CD1F29 /* skiplist.c */, 292 | ); 293 | path = util; 294 | sourceTree = ""; 295 | }; 296 | 099C798C2BBFF15000CD1F29 /* pci */ = { 297 | isa = PBXGroup; 298 | children = ( 299 | 099C798B2BBFF15000CD1F29 /* util.c */, 300 | ); 301 | path = pci; 302 | sourceTree = ""; 303 | }; 304 | 09DC13952BB196F900EBDE37 /* iommu */ = { 305 | isa = PBXGroup; 306 | children = ( 307 | 0942632E2BC0106D0038C603 /* context.c */, 308 | 09DC13902BB196F900EBDE37 /* dma.c */, 309 | 09DC13912BB196F900EBDE37 /* driverkit.c */, 310 | ); 311 | path = iommu; 312 | sourceTree = ""; 313 | }; 314 | 09DE905A2BC7DCE20035961E /* x86_64 */ = { 315 | isa = PBXGroup; 316 | children = ( 317 | 09DE90592BC7DCE20035961E /* rdtsc.c */, 318 | ); 319 | path = x86_64; 320 | sourceTree = ""; 321 | }; 322 | 09DE905B2BC7DCE20035961E /* arch */ = { 323 | isa = PBXGroup; 324 | children = ( 325 | 09DE905A2BC7DCE20035961E /* x86_64 */, 326 | ); 327 | path = arch; 328 | sourceTree = ""; 329 | }; 330 | 09F93E502B10E115004694A2 /* MacVFNInstaller */ = { 331 | isa = PBXGroup; 332 | children = ( 333 | 09F93E512B10E115004694A2 /* AppDelegate.h */, 334 | 09F93E522B10E115004694A2 /* AppDelegate.m */, 335 | 09F93E542B10E116004694A2 /* Assets.xcassets */, 336 | 09F93E562B10E116004694A2 /* MainMenu.xib */, 337 | 09F93E592B10E116004694A2 /* main.m */, 338 | 09F93E5B2B10E116004694A2 /* MacVFNInstaller.entitlements */, 339 | ); 340 | path = MacVFNInstaller; 341 | sourceTree = ""; 342 | }; 343 | /* End PBXGroup section */ 344 | 345 | /* Begin PBXHeadersBuildPhase section */ 346 | 0922B0482B10CCC1009CC5FF /* Headers */ = { 347 | isa = PBXHeadersBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | 090B2FBD2B10D3420079CDF8 /* types.h in Headers */, 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | }; 354 | /* End PBXHeadersBuildPhase section */ 355 | 356 | /* Begin PBXNativeTarget section */ 357 | 0922B04C2B10CCC1009CC5FF /* MacVFN */ = { 358 | isa = PBXNativeTarget; 359 | buildConfigurationList = 0922B05A2B10CCC1009CC5FF /* Build configuration list for PBXNativeTarget "MacVFN" */; 360 | buildPhases = ( 361 | 0922B0482B10CCC1009CC5FF /* Headers */, 362 | 0922B0492B10CCC1009CC5FF /* Sources */, 363 | 0922B04A2B10CCC1009CC5FF /* Frameworks */, 364 | 0922B04B2B10CCC1009CC5FF /* Resources */, 365 | 0922B06B2B10CE53009CC5FF /* Embed Frameworks */, 366 | ); 367 | buildRules = ( 368 | ); 369 | dependencies = ( 370 | ); 371 | name = MacVFN; 372 | productName = MacVFN; 373 | productReference = 0922B04D2B10CCC1009CC5FF /* com.openmpdk.MacVFN.dext */; 374 | productType = "com.apple.product-type.driver-extension"; 375 | }; 376 | 09F93E4E2B10E115004694A2 /* MacVFNInstaller */ = { 377 | isa = PBXNativeTarget; 378 | buildConfigurationList = 09F93E5E2B10E116004694A2 /* Build configuration list for PBXNativeTarget "MacVFNInstaller" */; 379 | buildPhases = ( 380 | 09F93E4B2B10E115004694A2 /* Sources */, 381 | 09F93E4C2B10E115004694A2 /* Frameworks */, 382 | 09F93E4D2B10E115004694A2 /* Resources */, 383 | 09F93E642B10E3E5004694A2 /* Embed System Extensions */, 384 | ); 385 | buildRules = ( 386 | ); 387 | dependencies = ( 388 | 09F93E602B10E11B004694A2 /* PBXTargetDependency */, 389 | 09F93E632B10E3E5004694A2 /* PBXTargetDependency */, 390 | ); 391 | name = MacVFNInstaller; 392 | productName = MacVFNInstaller; 393 | productReference = 09F93E4F2B10E115004694A2 /* MacVFNInstaller.app */; 394 | productType = "com.apple.product-type.application"; 395 | }; 396 | /* End PBXNativeTarget section */ 397 | 398 | /* Begin PBXProject section */ 399 | 0922B0442B10CCC1009CC5FF /* Project object */ = { 400 | isa = PBXProject; 401 | attributes = { 402 | BuildIndependentTargetsInParallel = 1; 403 | LastUpgradeCheck = 1500; 404 | TargetAttributes = { 405 | 0922B04C2B10CCC1009CC5FF = { 406 | CreatedOnToolsVersion = 15.0.1; 407 | }; 408 | 09F93E4E2B10E115004694A2 = { 409 | CreatedOnToolsVersion = 15.0.1; 410 | }; 411 | }; 412 | }; 413 | buildConfigurationList = 0922B0472B10CCC1009CC5FF /* Build configuration list for PBXProject "MacVFN" */; 414 | compatibilityVersion = "Xcode 14.0"; 415 | developmentRegion = en; 416 | hasScannedForEncodings = 0; 417 | knownRegions = ( 418 | en, 419 | Base, 420 | ); 421 | mainGroup = 0922B0432B10CCC1009CC5FF; 422 | productRefGroup = 0922B04E2B10CCC1009CC5FF /* Products */; 423 | projectDirPath = ""; 424 | projectRoot = ""; 425 | targets = ( 426 | 0922B04C2B10CCC1009CC5FF /* MacVFN */, 427 | 09F93E4E2B10E115004694A2 /* MacVFNInstaller */, 428 | ); 429 | }; 430 | /* End PBXProject section */ 431 | 432 | /* Begin PBXResourcesBuildPhase section */ 433 | 0922B04B2B10CCC1009CC5FF /* Resources */ = { 434 | isa = PBXResourcesBuildPhase; 435 | buildActionMask = 2147483647; 436 | files = ( 437 | ); 438 | runOnlyForDeploymentPostprocessing = 0; 439 | }; 440 | 09F93E4D2B10E115004694A2 /* Resources */ = { 441 | isa = PBXResourcesBuildPhase; 442 | buildActionMask = 2147483647; 443 | files = ( 444 | 09F93E552B10E116004694A2 /* Assets.xcassets in Resources */, 445 | 09F93E582B10E116004694A2 /* MainMenu.xib in Resources */, 446 | ); 447 | runOnlyForDeploymentPostprocessing = 0; 448 | }; 449 | /* End PBXResourcesBuildPhase section */ 450 | 451 | /* Begin PBXSourcesBuildPhase section */ 452 | 0922B0492B10CCC1009CC5FF /* Sources */ = { 453 | isa = PBXSourcesBuildPhase; 454 | buildActionMask = 2147483647; 455 | files = ( 456 | 09DC13982BB196F900EBDE37 /* dma.c in Sources */, 457 | 095CB91C2B10F22900EA2A98 /* MacVFNUserClient.iig in Sources */, 458 | 090B2FDA2B10D3420079CDF8 /* pci.c in Sources */, 459 | 09DC13992BB196F900EBDE37 /* driverkit.c in Sources */, 460 | 090B2FD12B10D3420079CDF8 /* mem.c in Sources */, 461 | 090B2FC12B10D3420079CDF8 /* core.c in Sources */, 462 | 09DE90572BC7DB9D0035961E /* ticks.c in Sources */, 463 | 0942632F2BC0106D0038C603 /* context.c in Sources */, 464 | 09DE905D2BC7DCE30035961E /* rdtsc.c in Sources */, 465 | 090B2FBC2B10D3420079CDF8 /* util.c in Sources */, 466 | 090B2FBF2B10D3420079CDF8 /* rq.c in Sources */, 467 | 090B2FBE2B10D3420079CDF8 /* queue.c in Sources */, 468 | 095CB91E2B10F24500EA2A98 /* MacVFNUserClient.cpp in Sources */, 469 | 0922B0562B10CCC1009CC5FF /* MacVFN.iig in Sources */, 470 | 0922B0542B10CCC1009CC5FF /* MacVFN.cpp in Sources */, 471 | 099C798E2BBFF15000CD1F29 /* util.c in Sources */, 472 | 099C79882BBFEA1A00CD1F29 /* skiplist.c in Sources */, 473 | ); 474 | runOnlyForDeploymentPostprocessing = 0; 475 | }; 476 | 09F93E4B2B10E115004694A2 /* Sources */ = { 477 | isa = PBXSourcesBuildPhase; 478 | buildActionMask = 2147483647; 479 | files = ( 480 | 09F93E5A2B10E116004694A2 /* main.m in Sources */, 481 | 09F93E532B10E115004694A2 /* AppDelegate.m in Sources */, 482 | ); 483 | runOnlyForDeploymentPostprocessing = 0; 484 | }; 485 | /* End PBXSourcesBuildPhase section */ 486 | 487 | /* Begin PBXTargetDependency section */ 488 | 09F93E602B10E11B004694A2 /* PBXTargetDependency */ = { 489 | isa = PBXTargetDependency; 490 | target = 0922B04C2B10CCC1009CC5FF /* MacVFN */; 491 | targetProxy = 09F93E5F2B10E11B004694A2 /* PBXContainerItemProxy */; 492 | }; 493 | 09F93E632B10E3E5004694A2 /* PBXTargetDependency */ = { 494 | isa = PBXTargetDependency; 495 | target = 0922B04C2B10CCC1009CC5FF /* MacVFN */; 496 | targetProxy = 09F93E622B10E3E5004694A2 /* PBXContainerItemProxy */; 497 | }; 498 | /* End PBXTargetDependency section */ 499 | 500 | /* Begin PBXVariantGroup section */ 501 | 09F93E562B10E116004694A2 /* MainMenu.xib */ = { 502 | isa = PBXVariantGroup; 503 | children = ( 504 | 09F93E572B10E116004694A2 /* Base */, 505 | ); 506 | name = MainMenu.xib; 507 | sourceTree = ""; 508 | }; 509 | /* End PBXVariantGroup section */ 510 | 511 | /* Begin XCBuildConfiguration section */ 512 | 0922B0582B10CCC1009CC5FF /* Debug */ = { 513 | isa = XCBuildConfiguration; 514 | buildSettings = { 515 | ALWAYS_SEARCH_USER_PATHS = NO; 516 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 517 | CLANG_ANALYZER_NONNULL = YES; 518 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 519 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 520 | CLANG_ENABLE_MODULES = YES; 521 | CLANG_ENABLE_OBJC_ARC = YES; 522 | CLANG_ENABLE_OBJC_WEAK = YES; 523 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 524 | CLANG_WARN_BOOL_CONVERSION = YES; 525 | CLANG_WARN_COMMA = YES; 526 | CLANG_WARN_CONSTANT_CONVERSION = YES; 527 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 528 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 529 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 530 | CLANG_WARN_EMPTY_BODY = YES; 531 | CLANG_WARN_ENUM_CONVERSION = YES; 532 | CLANG_WARN_INFINITE_RECURSION = YES; 533 | CLANG_WARN_INT_CONVERSION = YES; 534 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 535 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 536 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 537 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 538 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 539 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 540 | CLANG_WARN_STRICT_PROTOTYPES = YES; 541 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 542 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 543 | CLANG_WARN_UNREACHABLE_CODE = YES; 544 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 545 | COPY_PHASE_STRIP = NO; 546 | DEBUG_INFORMATION_FORMAT = dwarf; 547 | DRIVERKIT_DEPLOYMENT_TARGET = 23.0; 548 | ENABLE_STRICT_OBJC_MSGSEND = YES; 549 | ENABLE_TESTABILITY = YES; 550 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 551 | GCC_C_LANGUAGE_STANDARD = gnu17; 552 | GCC_DYNAMIC_NO_PIC = NO; 553 | GCC_NO_COMMON_BLOCKS = YES; 554 | GCC_OPTIMIZATION_LEVEL = 0; 555 | GCC_PREPROCESSOR_DEFINITIONS = ( 556 | "DEBUG=1", 557 | "$(inherited)", 558 | ); 559 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 560 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 561 | GCC_WARN_UNDECLARED_SELECTOR = YES; 562 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 563 | GCC_WARN_UNUSED_FUNCTION = YES; 564 | GCC_WARN_UNUSED_VARIABLE = YES; 565 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 566 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 567 | MTL_FAST_MATH = YES; 568 | ONLY_ACTIVE_ARCH = YES; 569 | SDKROOT = driverkit; 570 | }; 571 | name = Debug; 572 | }; 573 | 0922B0592B10CCC1009CC5FF /* Release */ = { 574 | isa = XCBuildConfiguration; 575 | buildSettings = { 576 | ALWAYS_SEARCH_USER_PATHS = NO; 577 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 578 | CLANG_ANALYZER_NONNULL = YES; 579 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 580 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 581 | CLANG_ENABLE_MODULES = YES; 582 | CLANG_ENABLE_OBJC_ARC = YES; 583 | CLANG_ENABLE_OBJC_WEAK = YES; 584 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 585 | CLANG_WARN_BOOL_CONVERSION = YES; 586 | CLANG_WARN_COMMA = YES; 587 | CLANG_WARN_CONSTANT_CONVERSION = YES; 588 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 589 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 590 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 591 | CLANG_WARN_EMPTY_BODY = YES; 592 | CLANG_WARN_ENUM_CONVERSION = YES; 593 | CLANG_WARN_INFINITE_RECURSION = YES; 594 | CLANG_WARN_INT_CONVERSION = YES; 595 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 596 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 597 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 598 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 599 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 600 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 601 | CLANG_WARN_STRICT_PROTOTYPES = YES; 602 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 603 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 604 | CLANG_WARN_UNREACHABLE_CODE = YES; 605 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 606 | COPY_PHASE_STRIP = NO; 607 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 608 | DRIVERKIT_DEPLOYMENT_TARGET = 23.0; 609 | ENABLE_NS_ASSERTIONS = NO; 610 | ENABLE_STRICT_OBJC_MSGSEND = YES; 611 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 612 | GCC_C_LANGUAGE_STANDARD = gnu17; 613 | GCC_NO_COMMON_BLOCKS = YES; 614 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 615 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 616 | GCC_WARN_UNDECLARED_SELECTOR = YES; 617 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 618 | GCC_WARN_UNUSED_FUNCTION = YES; 619 | GCC_WARN_UNUSED_VARIABLE = YES; 620 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 621 | MTL_ENABLE_DEBUG_INFO = NO; 622 | MTL_FAST_MATH = YES; 623 | SDKROOT = driverkit; 624 | }; 625 | name = Release; 626 | }; 627 | 0922B05B2B10CCC1009CC5FF /* Debug */ = { 628 | isa = XCBuildConfiguration; 629 | buildSettings = { 630 | CODE_SIGN_IDENTITY = ""; 631 | CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO; 632 | CODE_SIGN_STYLE = Manual; 633 | CURRENT_PROJECT_VERSION = 1; 634 | DEVELOPMENT_TEAM = ""; 635 | GENERATE_INFOPLIST_FILE = YES; 636 | INFOPLIST_FILE = MacVFN/Info.plist; 637 | "LD_MAP_FILE_PATH[arch=*]" = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt"; 638 | MARKETING_VERSION = 1.0; 639 | OTHER_CFLAGS = ( 640 | "-I", 641 | "\"${SRCROOT}/MacVFN/libvfn/include/\"", 642 | "-I", 643 | "\"${SRCROOT}/MacVFN/libvfn/ccan/\"", 644 | "-I", 645 | "\"${SRCROOT}/MacVFN/libvfn/build/ccan/\"", 646 | "-I", 647 | "\"${SRCROOT}/MacVFN/libvfn/src/\"", 648 | ); 649 | PRODUCT_BUNDLE_IDENTIFIER = com.openmpdk.MacVFN; 650 | PRODUCT_NAME = "$(inherited)"; 651 | PROVISIONING_PROFILE_SPECIFIER = ""; 652 | RUN_CLANG_STATIC_ANALYZER = YES; 653 | SKIP_INSTALL = YES; 654 | SWIFT_EMIT_LOC_STRINGS = YES; 655 | }; 656 | name = Debug; 657 | }; 658 | 0922B05C2B10CCC1009CC5FF /* Release */ = { 659 | isa = XCBuildConfiguration; 660 | buildSettings = { 661 | CODE_SIGN_IDENTITY = ""; 662 | CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO; 663 | CODE_SIGN_STYLE = Manual; 664 | CURRENT_PROJECT_VERSION = 1; 665 | DEVELOPMENT_TEAM = ""; 666 | GENERATE_INFOPLIST_FILE = YES; 667 | INFOPLIST_FILE = MacVFN/Info.plist; 668 | MARKETING_VERSION = 1.0; 669 | OTHER_CFLAGS = ( 670 | "-I", 671 | "\"${SRCROOT}/MacVFN/libvfn/include/\"", 672 | "-I", 673 | "\"${SRCROOT}/MacVFN/libvfn/ccan/\"", 674 | "-I", 675 | "\"${SRCROOT}/MacVFN/libvfn/build/ccan/\"", 676 | "-I", 677 | "\"${SRCROOT}/MacVFN/libvfn/src/\"", 678 | ); 679 | PRODUCT_BUNDLE_IDENTIFIER = com.openmpdk.MacVFN; 680 | PRODUCT_NAME = "$(inherited)"; 681 | PROVISIONING_PROFILE_SPECIFIER = ""; 682 | RUN_CLANG_STATIC_ANALYZER = YES; 683 | SKIP_INSTALL = YES; 684 | SWIFT_EMIT_LOC_STRINGS = YES; 685 | }; 686 | name = Release; 687 | }; 688 | 09F93E5C2B10E116004694A2 /* Debug */ = { 689 | isa = XCBuildConfiguration; 690 | buildSettings = { 691 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 692 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 693 | CODE_SIGN_ENTITLEMENTS = MacVFNInstaller/MacVFNInstaller.entitlements; 694 | CODE_SIGN_IDENTITY = ""; 695 | CODE_SIGN_STYLE = Manual; 696 | COMBINE_HIDPI_IMAGES = YES; 697 | CURRENT_PROJECT_VERSION = 1; 698 | DEVELOPMENT_TEAM = ""; 699 | GENERATE_INFOPLIST_FILE = YES; 700 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 701 | INFOPLIST_KEY_NSMainNibFile = MainMenu; 702 | INFOPLIST_KEY_NSPrincipalClass = NSApplication; 703 | LD_RUNPATH_SEARCH_PATHS = ( 704 | "$(inherited)", 705 | "@executable_path/../Frameworks", 706 | ); 707 | MACOSX_DEPLOYMENT_TARGET = 14.0; 708 | MARKETING_VERSION = 1.0; 709 | PRODUCT_BUNDLE_IDENTIFIER = com.openmpdk.MacVFNInstaller; 710 | PRODUCT_NAME = "$(TARGET_NAME)"; 711 | PROVISIONING_PROFILE_SPECIFIER = ""; 712 | SDKROOT = macosx; 713 | SWIFT_EMIT_LOC_STRINGS = YES; 714 | }; 715 | name = Debug; 716 | }; 717 | 09F93E5D2B10E116004694A2 /* Release */ = { 718 | isa = XCBuildConfiguration; 719 | buildSettings = { 720 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 721 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 722 | CODE_SIGN_ENTITLEMENTS = MacVFNInstaller/MacVFNInstaller.entitlements; 723 | CODE_SIGN_IDENTITY = ""; 724 | CODE_SIGN_STYLE = Manual; 725 | COMBINE_HIDPI_IMAGES = YES; 726 | CURRENT_PROJECT_VERSION = 1; 727 | DEVELOPMENT_TEAM = ""; 728 | GENERATE_INFOPLIST_FILE = YES; 729 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 730 | INFOPLIST_KEY_NSMainNibFile = MainMenu; 731 | INFOPLIST_KEY_NSPrincipalClass = NSApplication; 732 | LD_RUNPATH_SEARCH_PATHS = ( 733 | "$(inherited)", 734 | "@executable_path/../Frameworks", 735 | ); 736 | MACOSX_DEPLOYMENT_TARGET = 14.0; 737 | MARKETING_VERSION = 1.0; 738 | PRODUCT_BUNDLE_IDENTIFIER = com.openmpdk.MacVFNInstaller; 739 | PRODUCT_NAME = "$(TARGET_NAME)"; 740 | PROVISIONING_PROFILE_SPECIFIER = ""; 741 | SDKROOT = macosx; 742 | SWIFT_EMIT_LOC_STRINGS = YES; 743 | }; 744 | name = Release; 745 | }; 746 | /* End XCBuildConfiguration section */ 747 | 748 | /* Begin XCConfigurationList section */ 749 | 0922B0472B10CCC1009CC5FF /* Build configuration list for PBXProject "MacVFN" */ = { 750 | isa = XCConfigurationList; 751 | buildConfigurations = ( 752 | 0922B0582B10CCC1009CC5FF /* Debug */, 753 | 0922B0592B10CCC1009CC5FF /* Release */, 754 | ); 755 | defaultConfigurationIsVisible = 0; 756 | defaultConfigurationName = Release; 757 | }; 758 | 0922B05A2B10CCC1009CC5FF /* Build configuration list for PBXNativeTarget "MacVFN" */ = { 759 | isa = XCConfigurationList; 760 | buildConfigurations = ( 761 | 0922B05B2B10CCC1009CC5FF /* Debug */, 762 | 0922B05C2B10CCC1009CC5FF /* Release */, 763 | ); 764 | defaultConfigurationIsVisible = 0; 765 | defaultConfigurationName = Release; 766 | }; 767 | 09F93E5E2B10E116004694A2 /* Build configuration list for PBXNativeTarget "MacVFNInstaller" */ = { 768 | isa = XCConfigurationList; 769 | buildConfigurations = ( 770 | 09F93E5C2B10E116004694A2 /* Debug */, 771 | 09F93E5D2B10E116004694A2 /* Release */, 772 | ); 773 | defaultConfigurationIsVisible = 0; 774 | defaultConfigurationName = Release; 775 | }; 776 | /* End XCConfigurationList section */ 777 | }; 778 | rootObject = 0922B0442B10CCC1009CC5FF /* Project object */; 779 | } 780 | -------------------------------------------------------------------------------- /MacVFN.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MacVFN.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MacVFN/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IOKitPersonalities 6 | 7 | MacVFN 8 | 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleIdentifierKernel 12 | com.apple.kpi.iokit 13 | IOClass 14 | IOUserService 15 | IOProviderClass 16 | IOPCIDevice 17 | IOUserClass 18 | MacVFN 19 | IOUserServerName 20 | com.openmpdk.MacVFN 21 | 22 | 23 | 24 | IOPCIClassMatch 25 | 0x01080200&0xfffffe00 26 | IOPCITunnelCompatible 27 | 28 | IOProbeScore 29 | 65530 30 | UserClientProperties 31 | 32 | IOClass 33 | IOUserUserClient 34 | IOUserClass 35 | MacVFNUserClient 36 | 37 | 38 | 39 | OSBundleUsageDescription 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /MacVFN/MacVFN.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MacVFN.cpp 3 | // MacVFN 4 | // 5 | // Created by Mads Ynddal on 24/11/2023. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "MacVFN.h" 18 | #include "MacVFNUserClient.h" 19 | #include "MacVFNShared.h" 20 | #include "MacVFNBuffers.h" 21 | 22 | #include 23 | #include "libvfn/src/iommu/context.h" 24 | 25 | #define MAX_QUEUE_COUNT 64 26 | 27 | struct MemoryDescriptorPair{ 28 | void *vaddr; 29 | IOBufferMemoryDescriptor *vaddr_descriptor; 30 | }; 31 | 32 | struct MacVFN_IVars 33 | { 34 | IOPCIDevice* pciDevice; 35 | 36 | struct MemoryDescriptorPair sq_buffer_descriptors[MAX_QUEUE_COUNT]; 37 | struct MemoryDescriptorPair cq_buffer_descriptors[MAX_QUEUE_COUNT]; 38 | RingQueue* cq_ring_queues[MAX_QUEUE_COUNT]; 39 | RingQueue* sq_ring_queues[MAX_QUEUE_COUNT]; 40 | 41 | int user_clients; 42 | 43 | struct nvme_ctrl ctrl; 44 | }; 45 | 46 | bool MacVFN::init(){ 47 | log_debug("MacVFN Init"); 48 | bool ret = super::init(); 49 | if (!ret) { 50 | log_debug("MacVFN: init failed"); 51 | return false; 52 | } 53 | 54 | ivars = IONewZero(MacVFN_IVars, 1); 55 | if (!ivars) { 56 | return false; 57 | } 58 | 59 | log_debug("MacVFN Init Done!"); 60 | return true; 61 | } 62 | 63 | void MacVFN::free(){ 64 | log_debug("MacVFN Free"); 65 | 66 | OSSafeReleaseNULL(ivars->ctrl.pci.dev); 67 | OSSafeReleaseNULL(ivars->ctrl.pci.iommu_mappings); 68 | OSSafeReleaseNULL(ivars->pciDevice); 69 | IOSafeDeleteNULL(ivars, MacVFN_IVars, 1); 70 | 71 | super::free(); 72 | } 73 | 74 | kern_return_t 75 | IMPL(MacVFN, Start) 76 | { 77 | log_debug("MacVFN: Start"); 78 | kern_return_t ret; 79 | ret = Start(provider, SUPERDISPATCH); 80 | if (ret != kIOReturnSuccess) { 81 | return kIOReturnNoDevice; 82 | } 83 | 84 | ivars->pciDevice = OSDynamicCast(IOPCIDevice, provider); 85 | if (ivars->pciDevice == NULL) { 86 | Stop(provider); 87 | return kIOReturnNoDevice; 88 | } 89 | ivars->pciDevice->retain(); 90 | 91 | ret = ivars->pciDevice->Open(this, 0); 92 | if (ret != kIOReturnSuccess) { 93 | Stop(provider); 94 | return kIOReturnNoDevice; 95 | } 96 | 97 | for (int qid = 0; qid < MAX_QUEUE_COUNT; qid++){ 98 | bzero((void*)&ivars->sq_buffer_descriptors[qid], sizeof(struct MemoryDescriptorPair)); 99 | bzero((void*)&ivars->cq_buffer_descriptors[qid], sizeof(struct MemoryDescriptorPair)); 100 | ivars->sq_ring_queues[qid] = NULL; 101 | ivars->cq_ring_queues[qid] = NULL; 102 | } 103 | 104 | ivars->ctrl = {}; 105 | ivars->ctrl.pci.dev = ivars->pciDevice; 106 | ivars->ctrl.pci.dev->retain(); 107 | ivars->ctrl.pci.iommu_mappings = OSDictionary::withCapacity(16); 108 | ::iommu_ctx_init(__iommu_ctx(&ivars->ctrl)); 109 | 110 | uint16_t commandRegister; 111 | ivars->pciDevice->ConfigurationRead16(kIOPCIConfigurationOffsetCommand, &commandRegister); 112 | commandRegister |= (kIOPCICommandBusMaster | kIOPCICommandMemorySpace); 113 | ivars->pciDevice->ConfigurationWrite16(kIOPCIConfigurationOffsetCommand, commandRegister); 114 | 115 | int nvme_ret = MacVFN::nvme_init(); 116 | if (nvme_ret) { 117 | return kIOReturnNoDevice; 118 | } 119 | 120 | IOServiceName service_name; 121 | memcpy((void*)service_name, (void*)"MacVFN-", 8); 122 | memcpy(service_name+7, ivars->ctrl.serial, 20); 123 | for (int i=0; i < 128; i++){ 124 | if (service_name[i] == ' ') { 125 | service_name[i] = '\0'; 126 | break; 127 | } 128 | } 129 | service_name[127] = '\0'; 130 | SetName(service_name); 131 | 132 | MacVFN::nvme_close_all(); 133 | 134 | log_debug("RegisterService"); 135 | RegisterService(); 136 | 137 | log_debug("Driver started!"); 138 | return ret; 139 | } 140 | 141 | kern_return_t 142 | IMPL(MacVFN, Stop) { 143 | log_debug("MacVFN: Stop"); 144 | 145 | if (ivars->ctrl.pci.dev) { 146 | ivars->ctrl.pci.dev->release(); 147 | ivars->ctrl.pci.dev = NULL; 148 | } 149 | 150 | OSSafeReleaseNULL(ivars->ctrl.pci.iommu_mappings); 151 | 152 | if (ivars->pciDevice) { 153 | 154 | uint16_t commandRegister; 155 | ivars->pciDevice->ConfigurationRead16(kIOPCIConfigurationOffsetCommand, &commandRegister); 156 | commandRegister &= ~(kIOPCICommandBusMaster | kIOPCICommandMemorySpace); 157 | ivars->pciDevice->ConfigurationWrite16(kIOPCIConfigurationOffsetCommand, commandRegister); 158 | 159 | ivars->pciDevice->Close(this, 0); 160 | } 161 | 162 | return Stop(provider, SUPERDISPATCH); 163 | } 164 | 165 | kern_return_t 166 | IMPL(MacVFN, NewUserClient) 167 | { 168 | log_debug("NewUserClient"); 169 | IOService* client = nullptr; 170 | kern_return_t ret = kIOReturnSuccess; 171 | 172 | if (type != MACVFN_CLIENT_VERSION){ 173 | log_error("NewUserClient client version mismatch! Theirs: %08x Ours: %08x", type, MACVFN_CLIENT_VERSION); 174 | return kIOReturnError; 175 | } 176 | 177 | if (ivars->user_clients){ 178 | log_error("UserClient already created. Multiple userclients are not supported at this moment."); 179 | return kIOReturnError; 180 | } 181 | 182 | ret = Create(this, "UserClientProperties", &client); 183 | if (ret != kIOReturnSuccess) { 184 | log_debug("MacVFNDEXT this->Create: ret %x", ret); 185 | return ret; 186 | } 187 | 188 | *userClient = OSDynamicCast(IOUserClient, client); 189 | if (!(*userClient)) { 190 | client->release(); 191 | log_debug("MacVFNDEXT userClient error"); 192 | return kIOReturnError; 193 | } 194 | ivars->user_clients += 1; 195 | 196 | log_debug("NewUserClient successful"); 197 | 198 | return kIOReturnSuccess; 199 | } 200 | 201 | 202 | static inline kern_return_t libvfn_to_kern_return(int ret){ 203 | if (ret == 0){ 204 | return kIOReturnSuccess; 205 | } 206 | else{ 207 | return kIOReturnError; 208 | } 209 | } 210 | 211 | int MacVFN::dma_map_buffer(IOMemoryDescriptor* mem, void *vaddr, size_t len){ 212 | log_debug("MacVFN::dma_map_buffer %p %zx", mem, len); 213 | uint64_t iova; 214 | return ::_iommu_map_vaddr(__iommu_ctx(&ivars->ctrl.pci), vaddr, len, &iova, IOMMU_MAP_FIXED_IOVA, (void*) mem); 215 | } 216 | 217 | int MacVFN::dma_unmap_buffer(IOMemoryDescriptor* mem, void *vaddr){ 218 | log_debug("MacVFN::dma_unmap_buffer %p", mem); 219 | return ::iommu_unmap_vaddr(__iommu_ctx(&ivars->ctrl.pci), vaddr, NULL); 220 | } 221 | 222 | uint32_t MacVFN::nvme_init() 223 | { 224 | kern_return_t ret; 225 | ret = ivars->ctrl.pci.dev->GetBARInfo(kPCIMemoryRangeBAR0, &ivars->ctrl.pci.bar_region_info[0].memory_index, &ivars->ctrl.pci.bar_region_info[0].size, &ivars->ctrl.pci.bar_region_info[0].type); 226 | if(ret != kIOReturnSuccess) { 227 | log_debug("bar0 failed"); 228 | return kIOReturnNoDevice; 229 | } 230 | log_debug("bar0 info: %x, %llx, %x", ivars->ctrl.pci.bar_region_info[0].memory_index, ivars->ctrl.pci.bar_region_info[0].size, ivars->ctrl.pci.bar_region_info[0].type); 231 | 232 | int nvme_ret = ::nvme_init(&ivars->ctrl, "0000:00:00.0", NULL); 233 | return libvfn_to_kern_return(nvme_ret); 234 | } 235 | 236 | uint32_t MacVFN::nvme_oneshot(NvmeSubmitCmd* cmd, void* vaddr) 237 | { 238 | struct nvme_sq *sq; 239 | if (cmd->queue_id == 0){ 240 | sq = ivars->ctrl.adminq.sq; 241 | } 242 | else{ 243 | sq = &ivars->ctrl.sq[cmd->queue_id]; 244 | } 245 | log_debug("MacVFN::nvme_oneshot %llx, %llx, %llx", (uint64_t)sq, (uint64_t) cmd->cmd, (uint64_t) cmd->cpl); 246 | int nvme_ret = ::nvme_sync(&ivars->ctrl, sq, (union nvme_cmd*)&cmd->cmd, vaddr, cmd->dbuf_nbytes, (struct nvme_cqe *) &cmd->cpl); 247 | return libvfn_to_kern_return(nvme_ret); 248 | } 249 | 250 | uint32_t MacVFN::nvme_create_ioqpair(NvmeQueue* queue) 251 | { 252 | log_debug("nvme_create_ioqpair id: %llu vector: %llu", queue->id, queue->vector); 253 | 254 | if (queue->id >= MAX_QUEUE_COUNT){ 255 | log_debug("nvme_create_ioqpair queue id larger than fixed max: %llu (zero-indexed) of max count %d", queue->id, MAX_QUEUE_COUNT); 256 | return kIOReturnBadArgument; 257 | } 258 | 259 | int ret = ::nvme_create_ioqpair(&ivars->ctrl, queue->id, queue->depth + 1, queue->vector, queue->flags); 260 | 261 | if (ret){ 262 | return kIOReturnError; 263 | } 264 | 265 | struct MemoryDescriptorPair *sq_ring_desc = &ivars->sq_buffer_descriptors[queue->id]; 266 | struct MemoryDescriptorPair *cq_ring_desc = &ivars->cq_buffer_descriptors[queue->id]; 267 | RingQueue** sq_ring = &ivars->sq_ring_queues[queue->id]; 268 | RingQueue** cq_ring = &ivars->cq_ring_queues[queue->id]; 269 | 270 | size_t len; 271 | len = ::__pgmap((void**)&sq_ring_desc->vaddr, (queue->depth + 1)*sizeof(NvmeSubmitCmd) + sizeof(RingQueue), (void**) &sq_ring_desc->vaddr_descriptor); 272 | assert(len > 0); 273 | sq_ring_desc->vaddr_descriptor->retain(); 274 | (*sq_ring) = (RingQueue*)sq_ring_desc->vaddr; 275 | (*sq_ring)->buffer_size = len; 276 | (*sq_ring)->depth = queue->depth; 277 | 278 | len = ::__pgmap((void**)&cq_ring_desc->vaddr, (queue->depth + 1)*sizeof(NvmeSubmitCmd) + sizeof(RingQueue), (void**) &cq_ring_desc->vaddr_descriptor); 279 | assert(len > 0); 280 | cq_ring_desc->vaddr_descriptor->retain(); 281 | (*cq_ring) = (RingQueue*)cq_ring_desc->vaddr; 282 | (*cq_ring)->buffer_size = len; 283 | (*cq_ring)->depth = queue->depth; 284 | 285 | return libvfn_to_kern_return(ret); 286 | } 287 | 288 | uint32_t MacVFN::nvme_delete_ioqpair(NvmeQueue* queue) 289 | { 290 | log_debug("nvme_delete_ioqpair id: %llu", queue->id); 291 | 292 | if (queue->id > MAX_QUEUE_COUNT){ 293 | log_debug("nvme_delete_ioqpair queue id larger than fixed max: %llu/%d", queue->id, MAX_QUEUE_COUNT); 294 | return kIOReturnBadArgument; 295 | } 296 | 297 | int ret = ::nvme_delete_ioqpair(&ivars->ctrl, queue->id); 298 | 299 | if (ret){ 300 | return kIOReturnError; 301 | } 302 | 303 | IOBufferMemoryDescriptor** sq_ring_desc = &ivars->sq_buffer_descriptors[queue->id].vaddr_descriptor; 304 | IOBufferMemoryDescriptor** cq_ring_desc = &ivars->cq_buffer_descriptors[queue->id].vaddr_descriptor; 305 | void** sq_ring_vaddr = &ivars->sq_buffer_descriptors[queue->id].vaddr; 306 | void** cq_ring_vaddr = &ivars->cq_buffer_descriptors[queue->id].vaddr; 307 | RingQueue** sq_ring = &ivars->sq_ring_queues[queue->id]; 308 | RingQueue** cq_ring = &ivars->cq_ring_queues[queue->id]; 309 | 310 | (*sq_ring) = NULL; 311 | __pgunmap(*sq_ring_vaddr, 0, *(void**)sq_ring_desc); 312 | *sq_ring_desc = NULL; 313 | *sq_ring_vaddr = NULL; 314 | 315 | (*cq_ring) = NULL; 316 | __pgunmap(*cq_ring_vaddr, 0, *(void**)sq_ring_desc); 317 | *cq_ring_desc = NULL; 318 | *cq_ring_vaddr = NULL; 319 | 320 | return libvfn_to_kern_return(ret); 321 | } 322 | 323 | kern_return_t MacVFN::get_queue_buffer(uint32_t qid, uint32_t sq, IOMemoryDescriptor **memory) { 324 | IOBufferMemoryDescriptor* buffer; 325 | if (sq){ 326 | buffer = ivars->sq_buffer_descriptors[qid].vaddr_descriptor; 327 | } 328 | else { 329 | buffer = ivars->cq_buffer_descriptors[qid].vaddr_descriptor; 330 | } 331 | 332 | if (!buffer){ 333 | log_error("Failed to locate buffer for qid: %x, %x", qid, sq); 334 | return kIOReturnInvalid; 335 | } 336 | *memory = buffer; 337 | return kIOReturnSuccess; 338 | } 339 | 340 | 341 | kern_return_t MacVFN::poke(uint32_t sqid, uint32_t cqid, struct buffer* buffers) { 342 | kern_return_t ret; 343 | ret = process_sq(sqid, buffers); 344 | if (ret != kIOReturnSuccess){ 345 | return ret; 346 | } 347 | ret = process_cq(cqid); 348 | if (ret != kIOReturnSuccess){ 349 | return ret; 350 | } 351 | 352 | return kIOReturnSuccess; 353 | } 354 | 355 | kern_return_t MacVFN::process_sq(uint32_t qid, struct buffer* buffers) { 356 | RingQueue* ring_sq = ivars->sq_ring_queues[qid]; 357 | 358 | NvmeSubmitCmd nvme_cmd; 359 | struct nvme_sq *sq; 360 | OSNumber* key; 361 | IOBufferMemoryDescriptor* mem; 362 | IOBufferMemoryDescriptor* _mem; 363 | if (qid == 0){ 364 | sq = ivars->ctrl.adminq.sq; 365 | } 366 | else{ 367 | sq = &ivars->ctrl.sq[qid]; 368 | } 369 | 370 | log_debug("process_sq: (qid %u) pre queue head/tail %llu/%llu/%llu", qid, ring_sq->head, ring_sq->tail, ring_sq->depth); 371 | int reaped = 0; 372 | uint64_t head, tail; 373 | int entries_ready = queue_dequeue_ready(ring_sq, &head, &tail); 374 | for (uint64_t i=head; i < head+entries_ready; i++){ 375 | uint64_t next = i % ring_sq->depth; 376 | queue_get_entry(ring_sq, next, &nvme_cmd); 377 | 378 | struct nvme_rq *rq; 379 | rq = ::nvme_rq_acquire_atomic(sq); 380 | rq->opaque = (void*) nvme_cmd.backend_opaque; 381 | mb(); 382 | 383 | uint64_t iova; 384 | if (nvme_cmd.dbuf_token) { 385 | struct buffer* buf = buffer_find(buffers, nvme_cmd.dbuf_token); 386 | if (!buf){ 387 | log_error("MacVFN::process_sq: Invalid dbuf_token!"); 388 | return kIOReturnError; 389 | } 390 | 391 | if (::_iommu_map_vaddr(__iommu_ctx(&ivars->ctrl), (void*) buf->vaddr, nvme_cmd.dbuf_nbytes, &iova, IOMMU_MAP_FIXED_IOVA, (void*) buf->buf_desc)) { 392 | log_error("FAILED: vfio_iommu_vaddr_to_iova()"); 393 | ::nvme_rq_release_atomic(rq); 394 | return kIOReturnError; 395 | } 396 | 397 | if (nvme_cmd.dbuf_offset){ 398 | iova += nvme_cmd.dbuf_offset; 399 | } 400 | 401 | ::nvme_rq_map_prp(&ivars->ctrl, rq, (union nvme_cmd *)&nvme_cmd.cmd, iova, nvme_cmd.dbuf_nbytes); 402 | } 403 | 404 | if (nvme_cmd.mbuf_token) { 405 | struct buffer* buf = buffer_find(buffers, nvme_cmd.mbuf_token); 406 | if (!buf){ 407 | log_error("MacVFN::process_sq: Invalid mbuf_token!"); 408 | return kIOReturnError; 409 | } 410 | 411 | if (::_iommu_map_vaddr(__iommu_ctx(&ivars->ctrl), (void*) buf->vaddr, nvme_cmd.mbuf_nbytes, &iova, IOMMU_MAP_FIXED_IOVA, (void*) buf->buf_desc)) { 412 | log_error("FAILED: vfio_iommu_vaddr_to_iova()"); 413 | ::nvme_rq_release_atomic(rq); 414 | return kIOReturnError; 415 | } 416 | 417 | if (nvme_cmd.mbuf_offset){ 418 | iova += nvme_cmd.mbuf_offset; 419 | } 420 | 421 | ((union nvme_cmd*) &nvme_cmd.cmd)->mptr = cpu_to_le64(iova); 422 | } 423 | ::nvme_rq_exec(rq, (union nvme_cmd *)&nvme_cmd.cmd); 424 | log_info("process_sq: opaque %x, %x, %llx", qid, rq->cid, (uint64_t) rq->opaque); 425 | assert(rq->opaque); 426 | reaped += 1; 427 | } 428 | 429 | assert(reaped == entries_ready); 430 | 431 | if (reaped){ 432 | mb(); 433 | uint64_t old_head = __c11_atomic_exchange(&ring_sq->head, (head+reaped) % ring_sq->depth, __ATOMIC_RELAXED); 434 | assert(old_head == head); 435 | } 436 | log_debug("process_sq: post queue head/tail %llu/%llu/%llu", ring_sq->head, ring_sq->tail, ring_sq->depth); 437 | 438 | return kIOReturnSuccess; 439 | } 440 | 441 | kern_return_t MacVFN::process_cq(uint32_t qid) { 442 | struct nvme_cq *cq; 443 | struct nvme_sq *sq; 444 | 445 | if (qid == 0){ 446 | cq = ivars->ctrl.adminq.cq; 447 | sq = ivars->ctrl.adminq.sq; 448 | } 449 | else{ 450 | cq = &ivars->ctrl.cq[qid]; 451 | sq = &ivars->ctrl.sq[qid]; 452 | } 453 | 454 | RingQueue* ring_cq = ivars->cq_ring_queues[qid]; 455 | int reaped = 0; 456 | NvmeSubmitCmd nvme_cmd; 457 | while (true) { 458 | if (queue_full(ring_cq)){ 459 | // Queue full 460 | break; 461 | } 462 | 463 | struct nvme_rq *rq; 464 | struct nvme_cqe *cqe; 465 | 466 | cqe = ::nvme_cq_get_cqe(cq); 467 | if (!cqe) { 468 | break; 469 | } 470 | 471 | reaped++; 472 | 473 | rq = ::__nvme_rq_from_cqe(sq, cqe); 474 | assert(rq->cid == cqe->cid); 475 | assert(rq->opaque); 476 | nvme_cmd.backend_opaque = (uint64_t)rq->opaque; 477 | 478 | memcpy(&nvme_cmd.cpl, cqe, sizeof(nvme_cmd.cpl)); 479 | assert(nvme_cmd.backend_opaque); 480 | assert(queue_enqueue(ring_cq, &nvme_cmd) == 0); 481 | mb(); 482 | nvme_rq_release_atomic(rq); 483 | } 484 | 485 | mb(); 486 | if (reaped) { 487 | log_debug("process_cq: Updating %d", reaped); 488 | nvme_cq_update_head(cq); 489 | } 490 | 491 | return kIOReturnSuccess; 492 | } 493 | 494 | void MacVFN::nvme_close_all(){ 495 | ::nvme_close(&ivars->ctrl); 496 | 497 | for (int qid = 0; qid < MAX_QUEUE_COUNT; qid++){ 498 | OSSafeReleaseNULL(ivars->sq_buffer_descriptors[qid].vaddr_descriptor); 499 | OSSafeReleaseNULL(ivars->cq_buffer_descriptors[qid].vaddr_descriptor); 500 | ivars->sq_buffer_descriptors[qid].vaddr = NULL; 501 | ivars->cq_buffer_descriptors[qid].vaddr = NULL; 502 | 503 | // These are derived pointers and are released by the descriptors above 504 | ivars->sq_ring_queues[qid] = NULL; 505 | ivars->cq_ring_queues[qid] = NULL; 506 | } 507 | 508 | log_info("IOMMU Mapping still have %u entries", ivars->ctrl.pci.iommu_mappings->getCount()); 509 | 510 | ::iommu_unmap_all(__iommu_ctx(&ivars->ctrl.pci)); 511 | } 512 | 513 | void MacVFN::stop_userclient(){ 514 | nvme_close_all(); 515 | ivars->user_clients -= 1; 516 | } 517 | -------------------------------------------------------------------------------- /MacVFN/MacVFN.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.developer.driverkit 8 | 9 | com.apple.developer.driverkit.transport.pci 10 | 11 | com.apple.developer.driverkit.transport.pci.bridge 12 | 13 | com.apple.developer.driverkit.allow-any-userclient-access 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /MacVFN/MacVFN.iig: -------------------------------------------------------------------------------- 1 | // 2 | // MacVFN.iig 3 | // MacVFN 4 | // 5 | // Created by Mads Ynddal on 24/11/2023. 6 | // 7 | 8 | #ifndef MacVFN_h 9 | #define MacVFN_h 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "MacVFNShared.h" 21 | 22 | class MacVFN: public IOService 23 | { 24 | public: 25 | virtual bool init() override; 26 | virtual void free() override; 27 | virtual kern_return_t 28 | Start(IOService * provider) override; 29 | virtual kern_return_t 30 | Stop(IOService * provider) override; 31 | virtual kern_return_t 32 | NewUserClient(uint32_t type, IOUserClient **userClient) override; 33 | 34 | // Helpers for UserClient 35 | uint32_t nvme_init() LOCALONLY; 36 | uint32_t nvme_oneshot(NvmeSubmitCmd* cmd, void* vaddr) LOCALONLY; 37 | uint32_t nvme_create_ioqpair(NvmeQueue* queue) LOCALONLY; 38 | uint32_t nvme_delete_ioqpair(NvmeQueue* queue) LOCALONLY; 39 | int dma_map_buffer(IOMemoryDescriptor* mem, void *vaddr, size_t len) LOCALONLY; 40 | int dma_unmap_buffer(IOMemoryDescriptor* mem, void *vaddr) LOCALONLY; 41 | kern_return_t get_queue_buffer(uint32_t qid, uint32_t sq, IOMemoryDescriptor **memory) LOCALONLY; 42 | kern_return_t poke(uint32_t sqid, uint32_t cqid, struct buffer* buffers) LOCALONLY; 43 | kern_return_t process_sq(uint32_t qid, struct buffer* buffers) LOCALONLY; 44 | kern_return_t process_cq(uint32_t qid) LOCALONLY; 45 | void stop_userclient() LOCALONLY; 46 | void nvme_close_all() LOCALONLY; 47 | }; 48 | 49 | #endif /* MacVFN_h */ 50 | -------------------------------------------------------------------------------- /MacVFN/MacVFNBuffers.h: -------------------------------------------------------------------------------- 1 | // 2 | // MacVFNBuffers.h 3 | // MacVFN 4 | // 5 | // Created by Mads Ynddal on 25/10/2024. 6 | // 7 | 8 | #ifndef MacVFNBuffers_h 9 | #define MacVFNBuffers_h 10 | struct buffer { 11 | uint64_t token; 12 | IOMemoryDescriptor *buf_desc; 13 | uint64_t vaddr; 14 | bool in_use; 15 | }; 16 | 17 | #define MAX_BUFFERS 256 18 | 19 | static bool buffer_add(struct buffer *buffers, struct buffer _new){ 20 | for (int i=0; iin_use && (buf->token == token)){ 34 | buf->in_use = false; 35 | return true; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | static struct buffer* buffer_find(struct buffer *buffers, uint64_t token){ 42 | for (int i=0; iin_use && (buf->token == token)){ 45 | return buf; 46 | } 47 | } 48 | return NULL; 49 | } 50 | 51 | static size_t buffer_count(struct buffer *buffers){ 52 | size_t count = 0; 53 | for (int i=0; ibuffer + sizeof(*cmd)*index, sizeof(*cmd)); 59 | } 60 | 61 | static inline void queue_put_entry(RingQueue *queue, uint64_t index, NvmeSubmitCmd* cmd){ 62 | memcpy((uint8_t*)queue->buffer + sizeof(*cmd)*index, (void*)cmd, sizeof(*cmd)); 63 | } 64 | 65 | #define QUEUE_FULL -1 66 | #define QUEUE_EMPTY -2 67 | #define QUEUE_ERROR -3 68 | 69 | static inline int queue_enqueue(RingQueue *queue, NvmeSubmitCmd* cmd){ 70 | uint64_t tail = __c11_atomic_load(&queue->tail, __ATOMIC_ACQUIRE); 71 | uint64_t head = __c11_atomic_load(&queue->head, __ATOMIC_RELAXED); 72 | 73 | if ((tail + 1) % queue->depth == head) { 74 | // Queue full 75 | return QUEUE_FULL; 76 | } 77 | 78 | queue_put_entry(queue, tail, cmd); 79 | 80 | uint64_t new_tail = (tail+1) % queue->depth; 81 | if (tail != __c11_atomic_exchange(&queue->tail, new_tail, __ATOMIC_RELEASE)){ 82 | // No way of recovering. Somebody else modified queue at the same time. 83 | return QUEUE_ERROR; 84 | } 85 | return 0; 86 | } 87 | 88 | static inline int queue_dequeue(RingQueue *queue, NvmeSubmitCmd* cmd){ 89 | uint64_t head = __c11_atomic_load(&queue->head, __ATOMIC_ACQUIRE); 90 | uint64_t tail = __c11_atomic_load(&queue->tail, __ATOMIC_RELAXED); 91 | 92 | if (head == tail) { 93 | // Queue empty 94 | return QUEUE_EMPTY; 95 | } 96 | 97 | queue_get_entry(queue, head, cmd); 98 | 99 | uint64_t new_head = (head+1) % queue->depth; 100 | if (head != __c11_atomic_exchange(&queue->head, new_head, __ATOMIC_RELEASE)){ 101 | // No way of recovering. Somebody else modified queue at the same time. 102 | return QUEUE_ERROR; 103 | } 104 | return 0; 105 | } 106 | 107 | static inline bool queue_full(RingQueue *queue){ 108 | uint64_t head = __c11_atomic_load(&queue->head, __ATOMIC_RELAXED); 109 | uint64_t tail = __c11_atomic_load(&queue->tail, __ATOMIC_RELAXED); 110 | return (tail + 1) % queue->depth == head; 111 | } 112 | 113 | static inline int queue_peek(RingQueue *queue){ 114 | uint64_t head = __c11_atomic_load(&queue->head, __ATOMIC_RELAXED); 115 | uint64_t tail = __c11_atomic_load(&queue->tail, __ATOMIC_RELAXED); 116 | return ((int64_t)head - (int64_t)tail + (int64_t)queue->depth) % (int64_t)queue->depth; 117 | } 118 | 119 | static inline int queue_dequeue_ready(RingQueue *queue, uint64_t *head, uint64_t *tail){ 120 | *head = __c11_atomic_load(&queue->head, __ATOMIC_RELAXED); 121 | *tail = __c11_atomic_load(&queue->tail, __ATOMIC_RELAXED); 122 | return ((int64_t)*tail - (int64_t)*head + (int64_t)queue->depth) % (int64_t)queue->depth; 123 | } 124 | 125 | static inline int queue_enqueue_ready(RingQueue *queue, uint64_t *head, uint64_t *tail){ 126 | *head = __c11_atomic_load(&queue->head, __ATOMIC_RELAXED); 127 | *tail = __c11_atomic_load(&queue->tail, __ATOMIC_RELAXED); 128 | return ((int64_t)*head - (int64_t)*tail + (int64_t)queue->depth) % (int64_t)queue->depth; 129 | } 130 | 131 | #endif /* MacVFNShared_h */ 132 | -------------------------------------------------------------------------------- /MacVFN/MacVFNUserClient.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MacVFNUserClient.cpp 3 | // MacVFN 4 | // 5 | // Created by Mads Ynddal on 24/11/2023. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "MacVFN.h" 16 | #include "MacVFNUserClient.h" 17 | #include "MacVFNShared.h" 18 | #include "MacVFNBuffers.h" 19 | 20 | #include 21 | 22 | struct MacVFNUserClient_IVars 23 | { 24 | MacVFN* macvfn = nullptr; 25 | struct buffer buffers[MAX_BUFFERS]; 26 | }; 27 | 28 | bool MacVFNUserClient::init(){ 29 | log_debug("MacVFNUserClient Init"); 30 | kern_return_t result = super::init(); 31 | if(result != true) 32 | { 33 | log_debug("MacVFNUserClient: init failed"); 34 | return false; 35 | } 36 | 37 | ivars = IONewZero(MacVFNUserClient_IVars, 1); 38 | if(ivars == NULL) 39 | { 40 | log_debug("MacVFNUserClient: ivars failed"); 41 | return false; 42 | } 43 | 44 | memset(&ivars->buffers, 0, sizeof(struct buffer)* MAX_BUFFERS); 45 | log_debug("MacVFNUserClient Init Done!"); 46 | return true; 47 | } 48 | 49 | void MacVFNUserClient::free(){ 50 | log_debug("MacVFNUserClient Free"); 51 | IOSafeDeleteNULL(ivars, MacVFNUserClient_IVars, 1); 52 | super::free(); 53 | } 54 | 55 | kern_return_t 56 | IMPL(MacVFNUserClient, Start) 57 | { 58 | log_debug("MacVFNUserClient: Start"); 59 | kern_return_t ret; 60 | ret = Start(provider, SUPERDISPATCH); 61 | if(ret != kIOReturnSuccess) 62 | { 63 | return kIOReturnNoDevice; 64 | } 65 | 66 | ivars->macvfn = OSDynamicCast(MacVFN, provider); 67 | if(ivars->macvfn == NULL) 68 | { 69 | log_debug("MacVFNUserClient: Failed to cast provider"); 70 | Stop(provider); 71 | return kIOReturnNoDevice; 72 | } 73 | 74 | return kIOReturnSuccess; 75 | } 76 | 77 | kern_return_t 78 | IMPL(MacVFNUserClient, Stop) { 79 | log_debug("MacVFNUserClient Stop"); 80 | 81 | log_info("Buffers still have %zu entries", buffer_count(ivars->buffers)); 82 | 83 | for (int i=0; ibuffers[i]); 85 | 86 | if (!buf->in_use){ 87 | continue; 88 | } 89 | 90 | IOMemoryDescriptor *buffer = buf->buf_desc; 91 | 92 | log_debug("Attempt dma_unmap_buffer. Buffer might not be mapped, but that's ok."); 93 | ivars->macvfn->dma_unmap_buffer(buffer, (void*) buf->vaddr); 94 | 95 | // buffer->release(); 96 | 97 | buf->in_use = false; 98 | } 99 | 100 | ivars->macvfn->stop_userclient(); 101 | 102 | return Stop(provider, SUPERDISPATCH); 103 | } 104 | 105 | kern_return_t 106 | IMPL(MacVFNUserClient, CopyClientMemoryForType) //(uint64_t type, uint64_t *options, IOMemoryDescriptor **memory) 107 | { 108 | log_debug("IMPL(MacVFNUserClient, CopyClientMemoryForType): %llx -> %llx", (uint64_t) memory, (uint64_t) *memory); 109 | 110 | // https://developer.apple.com/documentation/driverkit/iouserclient/3325615-copyclientmemoryfortype 111 | // "For a given IOUserClient instance, calling CopyClientMemoryForType() with 112 | // a given type, should return the same IOMemoryDescriptor instance" 113 | 114 | uint32_t qid = type & 0xFFFF; 115 | uint32_t sq = (type >> 16) & 1; // True if sq else cq 116 | 117 | return ivars->macvfn->get_queue_buffer(qid, sq, memory); 118 | } 119 | 120 | const IOUserClientMethodDispatch externalMethodChecks[NUMBER_OF_EXTERNAL_METHODS] = { 121 | [NVME_INIT] = 122 | { 123 | .function = (IOUserClientMethodFunction) &MacVFNUserClient::StaticHandleNvmeInit, 124 | .checkCompletionExists = false, 125 | .checkScalarInputCount = 0, 126 | .checkStructureInputSize = 0, 127 | .checkScalarOutputCount = 0, 128 | .checkStructureOutputSize = 0, 129 | }, 130 | [NVME_ONESHOT] = 131 | { 132 | .function = (IOUserClientMethodFunction) &MacVFNUserClient::StaticHandleNvmeOneshot, 133 | .checkCompletionExists = false, 134 | .checkScalarInputCount = 0, 135 | .checkStructureInputSize = sizeof(NvmeSubmitCmd), 136 | .checkScalarOutputCount = 0, 137 | .checkStructureOutputSize = sizeof(NvmeSubmitCmd), 138 | }, 139 | [NVME_CREATE_QUEUE_PAIR] = 140 | { 141 | .function = (IOUserClientMethodFunction) &MacVFNUserClient::StaticHandleNvmeCreateQueuePair, 142 | .checkCompletionExists = false, 143 | .checkScalarInputCount = 0, 144 | .checkStructureInputSize = sizeof(NvmeQueue), 145 | .checkScalarOutputCount = 0, 146 | .checkStructureOutputSize = sizeof(NvmeQueue), 147 | }, 148 | [NVME_DELETE_QUEUE_PAIR] = 149 | { 150 | .function = (IOUserClientMethodFunction) &MacVFNUserClient::StaticHandleNvmeDeleteQueuePair, 151 | .checkCompletionExists = false, 152 | .checkScalarInputCount = 0, 153 | .checkStructureInputSize = sizeof(NvmeQueue), 154 | .checkScalarOutputCount = 0, 155 | .checkStructureOutputSize = 0, 156 | }, 157 | [NVME_ALLOC_BUFFER] = 158 | { 159 | .function = (IOUserClientMethodFunction) &MacVFNUserClient::StaticHandleNvmeAllocBuffer, 160 | .checkCompletionExists = false, 161 | .checkScalarInputCount = 0, 162 | .checkStructureInputSize = kIOUserClientVariableStructureSize, 163 | .checkScalarOutputCount = 0, 164 | .checkStructureOutputSize = 0, 165 | }, 166 | [NVME_DEALLOC_BUFFER] = 167 | { 168 | .function = (IOUserClientMethodFunction) &MacVFNUserClient::StaticHandleNvmeDeallocBuffer, 169 | .checkCompletionExists = false, 170 | .checkScalarInputCount = 0, 171 | .checkStructureInputSize = 8, 172 | .checkScalarOutputCount = 0, 173 | .checkStructureOutputSize = 0, 174 | }, 175 | [NVME_POKE] = 176 | { 177 | .function = (IOUserClientMethodFunction) &MacVFNUserClient::StaticHandleNvmePoke, 178 | .checkCompletionExists = false, 179 | .checkScalarInputCount = 2, 180 | .checkStructureInputSize = 0, 181 | .checkScalarOutputCount = 0, 182 | .checkStructureOutputSize = 0, 183 | }, 184 | }; 185 | 186 | kern_return_t MacVFNUserClient::ExternalMethod(uint64_t selector, IOUserClientMethodArguments* arguments, const IOUserClientMethodDispatch* dispatch, OSObject* target, void* reference) 187 | { 188 | kern_return_t ret = kIOReturnSuccess; 189 | log_debug("MacVFNUserClient ExternalMethod %llu", selector); 190 | 191 | if (selector < NUMBER_OF_EXTERNAL_METHODS) { 192 | dispatch = &externalMethodChecks[selector]; 193 | if (!target) { 194 | target = this; 195 | } 196 | } 197 | return super::ExternalMethod(selector, arguments, dispatch, target, reference); 198 | } 199 | 200 | kern_return_t MacVFNUserClient::StaticHandleNvmeInit(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) 201 | { 202 | log_debug("MacVFNUserClient StaticHandleNvmeInit"); 203 | if (target == nullptr) { 204 | log_debug("MacVFNUserClient StaticHandleNvmeInit: Target null"); 205 | return kIOReturnError; 206 | } 207 | 208 | return ((MacVFNUserClient*)target)->HandleNvmeInit(reference, arguments); 209 | } 210 | 211 | kern_return_t MacVFNUserClient::HandleNvmeInit(void* reference, IOUserClientMethodArguments* arguments) 212 | { 213 | kern_return_t ret = kIOReturnSuccess; 214 | log_debug("MacVFNUserClient HandleNvmeInit"); 215 | ivars->macvfn->nvme_init(); 216 | log_debug("MacVFNUserClient HandleNvmeInit Done"); 217 | return ret; 218 | } 219 | 220 | kern_return_t MacVFNUserClient::StaticHandleNvmeOneshot(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) 221 | { 222 | log_debug("MacVFNUserClient StaticHandleNvmeOneshot"); 223 | if (target == nullptr) { 224 | log_debug("MacVFNUserClient StaticHandleNvmeOneshot: Target null"); 225 | return kIOReturnError; 226 | } 227 | 228 | return ((MacVFNUserClient*)target)->HandleNvmeOneshot(reference, arguments); 229 | } 230 | 231 | kern_return_t MacVFNUserClient::HandleNvmeOneshot(void* reference, IOUserClientMethodArguments* arguments) 232 | { 233 | uint64_t vaddr; 234 | IOMemoryDescriptor *buffer; 235 | kern_return_t ret = kIOReturnSuccess; 236 | 237 | log_debug("MacVFNUserClient HandleNvmeOneshot"); 238 | NvmeSubmitCmd* nvme_cmd = (NvmeSubmitCmd*)arguments->structureInput->getBytesNoCopy(); 239 | 240 | log_debug("nvme_cmd->dbuf_token %llx", nvme_cmd->dbuf_token); 241 | if (nvme_cmd->dbuf_token) { 242 | struct buffer* buf = buffer_find(ivars->buffers, nvme_cmd->dbuf_token); 243 | if (!buf){ 244 | log_error("MacVFN::nvme_oneshot: Invalid dbuf_token!"); 245 | return kIOReturnError; 246 | } 247 | buffer = buf->buf_desc; 248 | vaddr = buf->vaddr + nvme_cmd->dbuf_offset; 249 | } 250 | else{ 251 | vaddr = 0; 252 | } 253 | 254 | log_debug("MacVFNUserClient HandleNvmeOneshot IOBufferMemoryDescriptor: %p, %llx", buffer, vaddr); 255 | uint64_t nvme_ret = ivars->macvfn->nvme_oneshot(nvme_cmd, (void*) vaddr); 256 | log_debug("MacVFNUserClient HandleNvmeOneshot: %llu", nvme_ret); 257 | 258 | arguments->structureOutput = OSData::withBytes(nvme_cmd, sizeof(NvmeSubmitCmd)); 259 | log_debug("MacVFNUserClient HandleNvmeOneshot Done"); 260 | return ret; 261 | } 262 | 263 | kern_return_t MacVFNUserClient::StaticHandleNvmeCreateQueuePair(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) 264 | { 265 | log_debug("MacVFNUserClient StaticHandleNvmeCreateQueuePair"); 266 | if (target == nullptr) { 267 | log_debug("MacVFNUserClient StaticHandleNvmeCreateQueuePair: Target null"); 268 | return kIOReturnError; 269 | } 270 | 271 | return ((MacVFNUserClient*)target)->HandleNvmeCreateQueuePair(reference, arguments); 272 | } 273 | 274 | kern_return_t MacVFNUserClient::HandleNvmeCreateQueuePair(void* reference, IOUserClientMethodArguments* arguments) 275 | { 276 | kern_return_t ret; 277 | 278 | log_debug("MacVFNUserClient HandleNvmeCreateQueuePair"); 279 | NvmeQueue* queue = (NvmeQueue*)arguments->structureInput->getBytesNoCopy(); 280 | 281 | ret = ivars->macvfn->nvme_create_ioqpair(queue); 282 | log_debug("MacVFNUserClient HandleNvmeCreateQueuePair: %d", ret); 283 | 284 | arguments->structureOutput = OSData::withBytes(queue, sizeof(NvmeQueue)); 285 | log_debug("MacVFNUserClient HandleNvmeCreateQueuePair Done"); 286 | return ret; 287 | } 288 | 289 | kern_return_t MacVFNUserClient::StaticHandleNvmeDeleteQueuePair(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) 290 | { 291 | log_debug("MacVFNUserClient StaticHandleNvmeDeleteQueuePair"); 292 | if (target == nullptr) { 293 | log_debug("MacVFNUserClient StaticHandleNvmeDeleteQueuePair: Target null"); 294 | return kIOReturnError; 295 | } 296 | 297 | return ((MacVFNUserClient*)target)->HandleNvmeDeleteQueuePair(reference, arguments); 298 | } 299 | 300 | kern_return_t MacVFNUserClient::HandleNvmeDeleteQueuePair(void* reference, IOUserClientMethodArguments* arguments) 301 | { 302 | kern_return_t ret; 303 | 304 | log_debug("MacVFNUserClient HandleNvmeDeleteQueuePair"); 305 | NvmeQueue* queue = (NvmeQueue*)arguments->structureInput->getBytesNoCopy(); 306 | 307 | ret = ivars->macvfn->nvme_delete_ioqpair(queue); 308 | log_debug("MacVFNUserClient HandleNvmeDeleteQueuePair: %d", ret); 309 | 310 | // arguments->structureOutput = OSData::withBytes(queue, sizeof(NvmeQueue)); 311 | log_debug("MacVFNUserClient HandleNvmeDeleteQueuePair Done"); 312 | return ret; 313 | } 314 | 315 | kern_return_t MacVFNUserClient::StaticHandleNvmeAllocBuffer(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) 316 | { 317 | log_debug("MacVFNUserClient StaticHandleNvmeAllocBuffer"); 318 | if (target == nullptr) { 319 | log_debug("MacVFNUserClient StaticHandleNvmeAllocBuffer: Target null"); 320 | return kIOReturnError; 321 | } 322 | 323 | return ((MacVFNUserClient*)target)->HandleNvmeAllocBuffer(reference, arguments); 324 | } 325 | 326 | kern_return_t MacVFNUserClient::HandleNvmeAllocBuffer(void* reference, IOUserClientMethodArguments* arguments) 327 | { 328 | kern_return_t ret = kIOReturnSuccess; 329 | log_debug("MacVFNUserClient HandleNvmeAllocBuffer"); 330 | 331 | if (arguments->structureInput){ 332 | return kIOReturnInvalid; 333 | } 334 | 335 | IOMemoryDescriptor *buffer = (IOMemoryDescriptor*)arguments->structureInputDescriptor; 336 | log_debug("MacVFNUserClient HandleNvmeAllocBuffer IOMemoryDescriptor: %lx", (uintptr_t)buffer); 337 | 338 | IOMemoryMap* map; 339 | buffer->CreateMapping(0, 0, 0, 0, 0, &map); 340 | uint64_t vaddr = map->GetAddress(); 341 | size_t nbytes = ((uint64_t*) vaddr)[0]; 342 | uint64_t token = ((uint64_t*) vaddr)[1]; 343 | // NOTE: We keep the vaddr just for iommu lookups. We actually never read/write the buffer. 344 | // map->release(); 345 | 346 | buffer_add(ivars->buffers, (struct buffer){.buf_desc=buffer, .vaddr=vaddr, .token=token}); 347 | 348 | log_debug("MacVFNUserClient HandleNvmeAllocBuffer token %llx", token); 349 | 350 | if (ivars->macvfn->dma_map_buffer(buffer, (void*) vaddr, nbytes)) { 351 | return kIOReturnError; 352 | } 353 | 354 | log_debug("MacVFNUserClient HandleNvmeAllocBuffer Done"); 355 | return ret; 356 | } 357 | 358 | 359 | kern_return_t MacVFNUserClient::StaticHandleNvmeDeallocBuffer(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) 360 | { 361 | log_debug("MacVFNUserClient StaticHandleNvmeDeallocBuffer"); 362 | if (target == nullptr) { 363 | log_debug("MacVFNUserClient StaticHandleNvmeDeallocBuffer: Target null"); 364 | return kIOReturnError; 365 | } 366 | 367 | return ((MacVFNUserClient*)target)->HandleNvmeDeallocBuffer(reference, arguments); 368 | } 369 | 370 | kern_return_t MacVFNUserClient::HandleNvmeDeallocBuffer(void* reference, IOUserClientMethodArguments* arguments) 371 | { 372 | kern_return_t ret = kIOReturnSuccess; 373 | log_debug("MacVFNUserClient HandleNvmeDeallocBuffer"); 374 | 375 | uint64_t token = *(uint64_t*)arguments->structureInput->getBytesNoCopy(); 376 | 377 | log_debug("MacVFNUserClient HandleNvmeDeallocBuffer key: %llx", token); 378 | 379 | struct buffer* buf = buffer_find(ivars->buffers, token); 380 | if (!buf){ 381 | log_error("MacVFNUserClient HandleNvmeDeallocBuffer: Tried to dealloc buffer with token: %llx", token); 382 | return kIOReturnError; 383 | } 384 | 385 | log_debug("Attept dma_unmap_buffer. Buffer might not be mapped, but that's ok."); 386 | if (ivars->macvfn->dma_unmap_buffer(buf->buf_desc, (void*) buf->vaddr)) { 387 | log_error("Internal error in dma_unmap_buffer"); 388 | return kIOReturnError; 389 | } 390 | 391 | buffer_remove(ivars->buffers, token); 392 | 393 | log_debug("MacVFNUserClient HandleNvmeDeallocBuffer Done"); 394 | return ret; 395 | } 396 | 397 | kern_return_t MacVFNUserClient::StaticHandleNvmePoke(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) 398 | { 399 | log_debug("MacVFNUserClient StaticHandleNvmePoke"); 400 | if (target == nullptr) { 401 | log_debug("MacVFNUserClient StaticHandleNvmePoke: Target null"); 402 | return kIOReturnError; 403 | } 404 | 405 | return ((MacVFNUserClient*)target)->HandleNvmePoke(reference, arguments); 406 | } 407 | 408 | kern_return_t MacVFNUserClient::HandleNvmePoke(void* reference, IOUserClientMethodArguments* arguments) 409 | { 410 | kern_return_t ret = ivars->macvfn->poke(arguments->scalarInput[0], arguments->scalarInput[1], ivars->buffers); 411 | return ret; 412 | } -------------------------------------------------------------------------------- /MacVFN/MacVFNUserClient.iig: -------------------------------------------------------------------------------- 1 | // 2 | // MacVFNUserClient.iig 3 | // MacVFN 4 | // 5 | // Created by Mads Ynddal on 24/11/2023. 6 | // 7 | 8 | #ifndef MacVFNUserClient_h 9 | #define MacVFNUserClient_h 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class MacVFNUserClient: public IOUserClient 17 | { 18 | protected: 19 | static kern_return_t StaticHandleNvmeInit(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 20 | static kern_return_t StaticHandleNvmeOneshot(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 21 | static kern_return_t StaticHandleNvmeCreateQueuePair(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 22 | static kern_return_t StaticHandleNvmeDeleteQueuePair(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 23 | static kern_return_t StaticHandleNvmeAllocBuffer(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 24 | static kern_return_t StaticHandleNvmeDeallocBuffer(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 25 | static kern_return_t StaticHandleNvmePoke(OSObject* target, void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 26 | 27 | kern_return_t HandleNvmeInit(void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 28 | kern_return_t HandleNvmeOneshot(void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 29 | kern_return_t HandleNvmeCreateQueuePair(void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 30 | kern_return_t HandleNvmeDeleteQueuePair(void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 31 | kern_return_t HandleNvmeAllocBuffer(void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 32 | kern_return_t HandleNvmeDeallocBuffer(void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 33 | kern_return_t HandleNvmePoke(void* reference, IOUserClientMethodArguments* arguments) LOCALONLY; 34 | public: 35 | virtual bool init() override; 36 | virtual void free() override; 37 | virtual kern_return_t Start(IOService * provider) override; 38 | virtual kern_return_t Stop(IOService * provider) override; 39 | virtual kern_return_t ExternalMethod(uint64_t selector, IOUserClientMethodArguments* arguments, const IOUserClientMethodDispatch* dispatch, OSObject* target, void* reference) override; 40 | virtual kern_return_t CopyClientMemoryForType(uint64_t type, uint64_t *options, IOMemoryDescriptor **memory) override; 41 | }; 42 | 43 | #endif /* MacVFNUserClient_h */ 44 | -------------------------------------------------------------------------------- /MacVFNInstaller/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MacVFNInstaller 4 | // 5 | // Created by Mads Ynddal on 24/11/2023. 6 | // 7 | 8 | #import 9 | 10 | @interface AppDelegate : NSObject 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /MacVFNInstaller/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MacVFNInstaller 4 | // 5 | // Created by Mads Ynddal on 24/11/2023. 6 | // 7 | 8 | #import "AppDelegate.h" 9 | 10 | @interface AppDelegate () 11 | 12 | @property (strong) IBOutlet NSWindow *window; 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 18 | // Insert code here to initialize your application 19 | } 20 | 21 | 22 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 23 | // Insert code here to tear down your application 24 | } 25 | 26 | 27 | - (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app { 28 | return YES; 29 | } 30 | 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /MacVFNInstaller/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /MacVFNInstaller/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /MacVFNInstaller/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /MacVFNInstaller/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | Default 539 | 540 | 541 | 542 | 543 | 544 | 545 | Left to Right 546 | 547 | 548 | 549 | 550 | 551 | 552 | Right to Left 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | Default 564 | 565 | 566 | 567 | 568 | 569 | 570 | Left to Right 571 | 572 | 573 | 574 | 575 | 576 | 577 | Right to Left 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | -------------------------------------------------------------------------------- /MacVFNInstaller/MacVFNInstaller.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | com.apple.developer.system-extension.install 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /MacVFNInstaller/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MacVFNInstaller 4 | // 5 | // Created by Mads Ynddal on 24/11/2023. 6 | // 7 | @import Foundation; 8 | @import SystemExtensions; 9 | #import 10 | 11 | @interface VFNSystemExtensionDelegate: NSObject 12 | @end 13 | 14 | @implementation VFNSystemExtensionDelegate 15 | - (void)request:(OSSystemExtensionRequest *)request 16 | didFinishWithResult:(OSSystemExtensionRequestResult)result { 17 | switch (result){ 18 | case OSSystemExtensionRequestCompleted: 19 | NSLog(@"Installation completed"); 20 | break; 21 | case OSSystemExtensionRequestWillCompleteAfterReboot: 22 | NSLog(@"Installation will complete after reboot"); 23 | break; 24 | default: 25 | NSLog(@"Unknown result in 'didFinishWithResult': %ld", result); 26 | } 27 | exit(0); 28 | } 29 | 30 | - (void)request:(OSSystemExtensionRequest *)request didFailWithError:(NSError *)error { 31 | NSLog(@"Error in 'didFailWithError': %@", [error localizedDescription]); 32 | exit(1); 33 | } 34 | 35 | - (void)requestNeedsUserApproval:(OSSystemExtensionRequest *)request { 36 | NSLog(@"Waiting for user approval..."); 37 | NSLog(@"If not prompted, check System Settings -> Privacy & Security"); 38 | } 39 | 40 | - (OSSystemExtensionReplacementAction)request:(OSSystemExtensionRequest *)request 41 | actionForReplacingExtension:(OSSystemExtensionProperties *)existing 42 | withExtension:(OSSystemExtensionProperties *)ext { 43 | return OSSystemExtensionReplacementActionReplace; 44 | } 45 | @end 46 | 47 | static VFNSystemExtensionDelegate* vfn_delegate; 48 | 49 | int main(int argc, const char * argv[]) { 50 | @autoreleasepool { 51 | vfn_delegate = [VFNSystemExtensionDelegate new]; 52 | OSSystemExtensionRequest* request = [OSSystemExtensionRequest activationRequestForExtension:@"com.openmpdk.MacVFN" queue:dispatch_get_main_queue()]; 53 | request.delegate = vfn_delegate; 54 | [OSSystemExtensionManager.sharedManager submitRequest:request]; 55 | } 56 | return NSApplicationMain(argc, argv); 57 | } 58 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: kill build-driver install log 2 | 3 | all: build 4 | 5 | # BUILD_CONFIG := Debug 6 | BUILD_CONFIG := Release 7 | _APP := $(shell xcodebuild -project MacVFN.xcodeproj -scheme MacVFNInstaller -configuration ${BUILD_CONFIG} -showBuildSettings | grep TARGET_BUILD_DIR | grep -oEi "\/.*") 8 | APP = ${_APP}/MacVFNInstaller.app 9 | LIBVFN := MacVFN/libvfn 10 | 11 | kill: 12 | @echo "Kill..." 13 | sudo killall com.openmpdk.MacVFN;: 14 | sudo killall lldb;: 15 | 16 | build: ${LIBVFN}/build/ccan/config.h ${LIBVFN}/src/nvme/crc64table.h build-driver sign-driver 17 | 18 | ${LIBVFN}/build/ccan/config.h: 19 | rm -rf ${LIBVFN}/build 20 | cd ${LIBVFN}; meson setup build -Dlibnvme=disabled 21 | sed -i '' '/HAVE_BUILTIN_TYPES_COMPATIBLE_P/d' ${LIBVFN}/build/ccan/config.h 22 | 23 | ${LIBVFN}/src/nvme/crc64table.h: 24 | clang ${LIBVFN}/lib/gentable-crc64.c -I ${LIBVFN}/build/ccan/ -I ${LIBVFN}/ccan/ -o gentable_crc64 25 | ./gentable_crc64 > ${LIBVFN}/src/nvme/crc64table.h 26 | rm gentable_crc64 27 | 28 | build-driver: 29 | @echo "Building..." 30 | xcodebuild -scheme MacVFNInstaller build -configuration ${BUILD_CONFIG} 31 | 32 | sign-driver: 33 | @echo "Signing..." 34 | codesign -s - -f --entitlements "MacVFN/MacVFN.entitlements" "${APP}/Contents/Library/SystemExtensions/com.openmpdk.MacVFN.dext" 35 | codesign -s - -f --entitlements "MacVFNInstaller/MacVFNInstaller.entitlements" "${APP}" 36 | 37 | install: 38 | @echo "Installing..." 39 | ${APP}/Contents/MacOS/MacVFNInstaller 40 | 41 | log: 42 | @echo "Logging..." 43 | log stream | grep 'MacVFN' 44 | 45 | clean: 46 | rm -rf ${LIBVFN}/build 47 | rm ${LIBVFN}/src/nvme/crc64table.h 48 | xcodebuild clean 49 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # MacVFN (BETA) 2 | This is a port of [libvfn](https://github.com/OpenMPDK/libvfn) for macOS and implemented into [xNVMe](https://github.com/OpenMPDK/xnvme). It utilizes DriverKit to hook an external PCI NVMe device (through PCIDriverKit), and allows user-space applications to take control of the device. 3 | 4 | **This is not suitable for production**, as it requires [disabling SIP](https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection?language=objc), and everything has to be self-signed. The code might also be buggy or have improper memory management, as this is just a proof-of-concept at this point. 5 | 6 | # State of the code 7 | Consider this a beta release. It works fine for prototyping, testing, and development. 8 | 9 | Although it's a port of libvfn, there is no way of running any of the example code from the libvfn project, as they heavily depend on Linux-only APIs. Instead, MacVFN has been implemented in xNVMe as a reference solution. All the examples from xNVMe should work. 10 | 11 | ## TODO list: 12 | 13 | * Interrupts 14 | * Timeouts 15 | * Register with [BlockStorageDeviceDriverKit](https://developer.apple.com/documentation/blockstoragedevicedriverkit) 16 | 17 | # Installation 18 | 19 | These are the basic steps to build and install the driver: 20 | 21 | 0. [Disable SIP](https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection?language=objc) 22 | 1. Run `systemextensionsctl developer on` to [allow System Extensions from any directory](https://developer.apple.com/documentation/driverkit/debugging_and_testing_system_extensions) 23 | 2. Identify the newest or matching tagged xNVMe version of MacVFN (or go with `master`) 24 | 3. Git clone this repo with submodules: `git clone --recurse-submodules --branch xnvme_vX.Y.Z https://github.com/SamsungDS/MacVFN.git` 25 | 4. Run `make build install kill log`, approve system extension and type sudo-password as needed 26 | 5. Clone xNVMe with the `next` branch: `git clone -b next https://github.com/xnvme/xnvme` 27 | 6. Run `make config build install` 28 | 7. Check your NVMe device enumerates `xnvme enum` 29 | 8. Then take the 'uri' and run a command: `xnvme idfy MacVFN-1234ABCD --cns 0 --be=driverkit` 30 | 9. Or two `xnvme_single_sync MacVFN-1234ABCD` 31 | 10. Or three `xnvme_single_async MacVFN-1234ABCD` 32 | 33 | Optionally, you can clone and build [fio](https://github.com/axboe/fio) with xNVMe support: 34 | 35 | 1. Git clone fio: `git clone https://github.com/axboe/fio` 36 | 2. Install GNU-make: `brew install make` 37 | 3. Use `gmake` to build it: `gmake -j` 38 | 4. Run a test: `./fio --name=test1 --iodepth=64 --rw=write --bs=512 --size=1GB --loops=1 --numjobs=1 --direct=1 --ioengine=xnvme --filename=MacVFN-1234ABCD --thread=1 --xnvme_dev_nsid=1 --xnvme_be=driverkit --xnvme_sync=driverkit --xnvme_async=driverkit --verify=crc32` 39 | --------------------------------------------------------------------------------