Use bespoke interfaces to communicate with wsldevicehost (#41099)
* Use bespoke interfaces to communicate with wsldevicehost * pr feedback: remove UTF-8 BOM and better device teardown/modify race handling * pr feedback: remove extra rpcrt4; fix test failures --------- Co-authored-by: Brian Perkins <bperkins@ntdev.microsoft.com>
Brian Perkins committed
Jul 17, 2026 at 12:03 UTC
a5b93397d024bcccc5e8874d38042800be22010e
24 files changed
+769
-330
CMakeLists.txt
+3
@@ -510,6 +510,7 @@ include_directories(${WSLDEPS_SOURCE_DIR}/include/schemas)
510
include_directories(${WSLDEPS_SOURCE_DIR}/include/lxcore)
511
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/shared/inc)
512
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/windows/inc)
513
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/src/windows/wsldevicehoststub/inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE})
514
include_directories(${CMAKE_CURRENT_BINARY_DIR}/src/windows/service/inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE})
515
include_directories(${CMAKE_CURRENT_BINARY_DIR}/src/windows/wslinstaller/inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE})
516
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/linux/init/inc)
@@ -534,8 +535,10 @@ add_subdirectory(nuget)
535
add_subdirectory(msixgluepackage)
536
add_subdirectory(msipackage)
537
add_subdirectory(msixinstaller)
538
+add_subdirectory(src/windows/wsldevicehoststub/inc)
539
add_subdirectory(src/windows/common)
540
add_subdirectory(src/windows/service)
541
+add_subdirectory(src/windows/wsldevicehoststub)
542
add_subdirectory(src/windows/wslcsession)
543
add_subdirectory(src/windows/wslinstaller/inc)
544
add_subdirectory(src/windows/wslinstaller/stub)
doc/docs/dev-loop.md
+1
-1
@@ -74,7 +74,7 @@ This will generate a `wsl.sln` file that you can build either with Visual Studio
74
Build parameters:
75
76
- `cmake . -A arm64`: Build a package for ARM64
77
-- `cmake . -DCMAKE_BUILD_TYPE=Release`: Build for release
77
+- `cmake . -DCMAKE_BUILD_TYPE=Release`: Build for release (paired with cmake --build . --config Release)
78
- `cmake . -DBUILD_BUNDLE=TRUE`: Build a bundle msix package (requires building ARM64 first)
79
80
Note: To build and deploy faster during development, see options in `UserConfig.cmake`.
msipackage/CMakeLists.txt
+2
-2
@@ -17,7 +17,7 @@ set(OUTPUT_PACKAGE ${BIN}/wsl.msi)
17
set(PACKAGE_WIX_IN ${CMAKE_CURRENT_LIST_DIR}/package.wix.in)
18
set(PACKAGE_WIX ${BIN}/package.wix)
19
set(CAB_CACHE ${BIN}/cab)
20
-set(WINDOWS_BINARIES wsl.exe;wslg.exe;wslhost.exe;wslrelay.exe;wslservice.exe;wslserviceproxystub.dll;wslinstall.dll;wslc.exe;wslcsession.exe)
20
+set(WINDOWS_BINARIES wsl.exe;wslg.exe;wslhost.exe;wslrelay.exe;wslservice.exe;wslserviceproxystub.dll;wsldevicehostproxystub.dll;wslinstall.dll;wslc.exe;wslcsession.exe)
21
if (WSL_BUILD_WSL_SETTINGS)
22
list(APPEND WINDOWS_BINARIES "wslsettings/wslsettings.dll;wslsettings/wslsettings.exe;libwsl.dll")
23
endif()
@@ -57,7 +57,7 @@ add_custom_command(
57
58
add_custom_target(msipackage DEPENDS ${OUTPUT_PACKAGE})
59
set_target_properties(msipackage PROPERTIES EXCLUDE_FROM_ALL FALSE SOURCES ${PACKAGE_WIX_IN})
60
-add_dependencies(msipackage wsl wslg wslservice wslhost wslrelay wslserviceproxystub init initramfs wslinstall msixgluepackage wslc wslcsession)
60
+add_dependencies(msipackage wsl wslg wslservice wslhost wslrelay wslserviceproxystub wsldevicehostproxystub init initramfs wslinstall msixgluepackage wslc wslcsession)
61
62
if (WSL_BUILD_WSL_SETTINGS)
63
add_dependencies(msipackage wslsettings libwsl)
msipackage/package.wix.in
+67
-21
@@ -32,6 +32,7 @@
32
<File Id="wslhost.exe" Name="wslhost.exe" Source="${PACKAGE_INPUT_DIR}/wslhost.exe" />
33
<File Id="wslrelay.exe" Name="wslrelay.exe" Source="${PACKAGE_INPUT_DIR}/wslrelay.exe" />
34
<File Id="wslserviceproxystub.dll" Name="wslserviceproxystub.dll" Source="${PACKAGE_INPUT_DIR}/wslserviceproxystub.dll" />
35
+ <File Id="wsldevicehostproxystub.dll" Name="wsldevicehostproxystub.dll" Source="${PACKAGE_INPUT_DIR}/wsldevicehostproxystub.dll" />
36
<File Id="wsldeps.dll" Name="wsldeps.dll" Source="${PACKAGE_INPUT_DIR}/wsldeps.dll" />
37
38
<File Id="NOTICE.txt" Name="NOTICE.txt" Source="${CMAKE_SOURCE_DIR}/NOTICE.txt" />
@@ -189,32 +190,67 @@
190
<RegistryValue Name="LaunchPermission" Value="${DCOM_PERMISSION}" Type="binary" />
191
</RegistryKey>
192
192
- <!-- WslDeviceHost_VirtioPmem -->
193
- <RegistryKey Root="HKCR" Key="CLSID\{ABB755FC-1B86-4255-83E2-E5787ABCF6C2}">
194
- <RegistryValue Value="WslDeviceHost_VirtioPmem" Type="string" />
195
- <RegistryValue Name="AppId" Value="{17696EAC-9568-4CF5-BB8C-82515AAD6C09}" Type="string"/>
193
+ <!-- WslDeviceHostProxyStub -->
194
+ <RegistryKey Root="HKCR" Key="Interface\{27394DCF-6383-4E4E-BB0A-C13D4E5F6071}">
195
+ <RegistryValue Value="IWslDeviceHost" Type="string" />
196
+ <RegistryKey Key="ProxyStubClsid32">
197
+ <RegistryValue Value="{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}" Type="string" />
198
+ </RegistryKey>
199
+ </RegistryKey>
200
+ <RegistryKey Root="HKCR" Key="Interface\{D2F47B8A-1E3C-4D9F-A6B5-7C8E9F0A1B2C}">
201
+ <RegistryValue Value="IWslDeviceHostCallback" Type="string" />
202
+ <RegistryKey Key="ProxyStubClsid32">
203
+ <RegistryValue Value="{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}" Type="string" />
204
+ </RegistryKey>
205
+ </RegistryKey>
206
+ <RegistryKey Root="HKCR" Key="Interface\{E3F58C9B-2F4D-4E0A-B7C6-8D9F0A1B2C3D}">
207
+ <RegistryValue Value="IWslVirtioNetDevice" Type="string" />
208
+ <RegistryKey Key="ProxyStubClsid32">
209
+ <RegistryValue Value="{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}" Type="string" />
210
+ </RegistryKey>
211
+ </RegistryKey>
212
+ <RegistryKey Root="HKCR" Key="Interface\{F406DACB-3050-4F1B-A8D7-9E0A1B2C3D4E}">
213
+ <RegistryValue Value="IWslVirtiofsDevice" Type="string" />
214
+ <RegistryKey Key="ProxyStubClsid32">
215
+ <RegistryValue Value="{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}" Type="string" />
216
+ </RegistryKey>
217
+ </RegistryKey>
218
+ <RegistryKey Root="HKCR" Key="Interface\{05172EBD-4161-4C2C-99E8-AF1B2C3D4E5F}">
219
+ <RegistryValue Value="IWslVirtioPmemDevice" Type="string" />
220
+ <RegistryKey Key="ProxyStubClsid32">
221
+ <RegistryValue Value="{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}" Type="string" />
222
+ </RegistryKey>
223
+ </RegistryKey>
224
+ <RegistryKey Root="HKCR" Key="Interface\{16283FCE-5272-4D3D-AAF9-B02C3D4E5F60}">
225
+ <RegistryValue Value="IWslVm" Type="string" />
226
+ <RegistryKey Key="ProxyStubClsid32">
227
+ <RegistryValue Value="{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}" Type="string" />
228
+ </RegistryKey>
229
+ </RegistryKey>
230
231
+ <RegistryKey Root="HKCR" Key="CLSID\{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}">
232
+ <RegistryValue Value="WslDeviceHostProxyStub" Type="string" />
233
<RegistryKey Key="InProcServer32">
198
- <RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
234
+ <RegistryValue Value="[INSTALLDIR]wsldevicehostproxystub.dll" Type="string" />
235
<RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
236
</RegistryKey>
237
</RegistryKey>
238
203
- <!-- WslDeviceHost_VirtioFs (admin) -->
204
- <RegistryKey Root="HKCR" Key="CLSID\{7e6ad219-d1b3-42d5-b8ee-d96324e64ff6}">
205
- <RegistryValue Value="WslDeviceHost_VirtioFs_Admin" Type="string"/>
239
+ <!-- WslDeviceHost -->
240
+ <RegistryKey Root="HKCR" Key="CLSID\{2C3E9A41-7B5D-4F18-93D6-A8C2E4F7B1D9}">
241
+ <RegistryValue Value="WslDeviceHost" Type="string" />
242
<RegistryValue Name="AppId" Value="{17696EAC-9568-4CF5-BB8C-82515AAD6C09}" Type="string"/>
243
244
<RegistryKey Key="InProcServer32">
209
- <RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string"/>
210
- <RegistryValue Name="ThreadingModel" Value="Both" Type="string"/>
245
+ <RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
246
+ <RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
247
</RegistryKey>
248
</RegistryKey>
249
214
- <!-- WslDeviceHost_VirtioFs -->
215
- <RegistryKey Root="HKCR" Key="CLSID\{60285AE6-AAF3-4456-B444-A6C2D0DEDA38}">
216
- <RegistryValue Value="WslDeviceHost_VirtioFs" Type="string" />
217
- <RegistryValue Name="AppId" Value="{17696EAC-9568-4CF5-BB8C-82515AAD6C09}" Type="string" />
250
+ <!-- WslDeviceHost for elevated activation -->
251
+ <RegistryKey Root="HKCR" Key="CLSID\{E3146082-A0DA-43A7-813B-A89EEE8C7628}">
252
+ <RegistryValue Value="WslDeviceHost_Admin" Type="string" />
253
+ <RegistryValue Name="AppId" Value="{17696EAC-9568-4CF5-BB8C-82515AAD6C09}" Type="string"/>
254
255
<RegistryKey Key="InProcServer32">
256
<RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
@@ -222,14 +258,25 @@
258
</RegistryKey>
259
</RegistryKey>
260
225
- <!-- WslDeviceHost_VirtioNet -->
226
- <RegistryKey Root="HKCR" Key="CLSID\{9E0D1898-CA63-424E-8D49-9D6067A36BCE}">
227
- <RegistryValue Value="WslDeviceHost_Net" Type="string" />
228
- <RegistryValue Name="AppId" Value="{17696EAC-9568-4CF5-BB8C-82515AAD6C09}" Type="string" />
261
+ <!-- WslDeviceHost without telemetry -->
262
+ <RegistryKey Root="HKCR" Key="CLSID\{4F9C8B23-D6E1-4A85-BF2A-E7C5D8F931A6}">
263
+ <RegistryValue Value="WslDeviceHost_NoTelemetry" Type="string"/>
264
+ <RegistryValue Name="AppId" Value="{17696EAC-9568-4CF5-BB8C-82515AAD6C09}" Type="string"/>
265
266
<RegistryKey Key="InProcServer32">
231
- <RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
232
- <RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
267
+ <RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string"/>
268
+ <RegistryValue Name="ThreadingModel" Value="Both" Type="string"/>
269
+ </RegistryKey>
270
+ </RegistryKey>
271
+
272
+ <!-- WslDeviceHost without telemetry for elevated activation -->
273
+ <RegistryKey Root="HKCR" Key="CLSID\{9C9C7131-D756-48FA-BD49-734E75AF37C0}">
274
+ <RegistryValue Value="WslDeviceHost_NoTelemetry_Admin" Type="string"/>
275
+ <RegistryValue Name="AppId" Value="{17696EAC-9568-4CF5-BB8C-82515AAD6C09}" Type="string"/>
276
+
277
+ <RegistryKey Key="InProcServer32">
278
+ <RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string"/>
279
+ <RegistryValue Name="ThreadingModel" Value="Both" Type="string"/>
280
</RegistryKey>
281
</RegistryKey>
282
@@ -803,4 +850,3 @@
850
<?endif?>
851
</Package>
852
</Wix>
806
-
packages.config
+1
-1
@@ -19,7 +19,7 @@
19
<package id="Microsoft.WSL.bsdtar" version="0.0.2-2" />
20
<package id="Microsoft.WSL.Dependencies.amd64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
21
<package id="Microsoft.WSL.Dependencies.arm64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
22
- <package id="Microsoft.WSL.DeviceHost" version="1.2.48-0" />
22
+ <package id="Microsoft.WSL.DeviceHost" version="1.2.51-0" />
23
<package id="Microsoft.WSL.Kernel" version="6.18.35.2-1" targetFramework="native" />
24
<package id="Microsoft.WSL.LinuxSdk" version="1.20.0" targetFramework="native" />
25
<package id="Microsoft.WSL.TestData" version="0.5.0" />
src/windows/common/CMakeLists.txt
+1
-1
@@ -147,7 +147,7 @@ set(HEADERS
147
)
148
149
add_library(common STATIC ${SOURCES} ${HEADERS})
150
-add_dependencies(common wslserviceidl localization wslservicemc wslinstalleridl yaml-cpp)
150
+add_dependencies(common wslserviceidl wsldevicehostidl localization wslservicemc wslinstalleridl yaml-cpp)
151
152
target_precompile_headers(common PRIVATE precomp.h)
153
set_target_properties(common PROPERTIES FOLDER windows)
src/windows/common/ConsommeNetworking.cpp
+135
-99
@@ -13,20 +13,107 @@ using wsl::core::ConsommeNetworking;
13
14
static constexpr auto c_eth0DeviceName = L"eth0";
15
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);
16
+static constexpr wsl::shared::string::MacAddress c_defaultClientMacAddress{0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
17
+static constexpr wsl::shared::string::MacAddress c_gatewayMacAddress{0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
18
+
19
+namespace {
20
+
21
+EthernetAddress ToEthernetAddress(const wsl::shared::string::MacAddress& address)
22
+{
23
+ EthernetAddress result{};
24
+ std::copy(address.begin(), address.end(), std::begin(result.bytes));
25
+ return result;
26
+}
27
+
28
+Ipv4Address ToIpv4Address(const SOCKADDR_INET& address)
29
+{
30
+ Ipv4Address result{};
31
+ if (address.si_family == AF_INET)
32
+ {
33
+ result.value = address.Ipv4.sin_addr.S_un.S_addr;
34
+ }
35
+
36
+ return result;
37
+}
38
+
39
+Ipv6Address ToIpv6Address(const SOCKADDR_INET& address)
40
+{
41
+ Ipv6Address result{};
42
+ if (address.si_family == AF_INET6)
43
+ {
44
+ std::copy(std::begin(address.Ipv6.sin6_addr.u.Byte), std::end(address.Ipv6.sin6_addr.u.Byte), std::begin(result.bytes));
45
+ }
46
+
47
+ return result;
48
+}
49
+
50
+IpAddress ToIpAddress(const SOCKADDR_INET& address)
51
+{
52
+ IpAddress result{};
53
+ if (address.si_family == AF_INET)
54
+ {
55
+ result.family = IpAddressFamily_V4;
56
+ std::copy(
57
+ reinterpret_cast<const BYTE*>(&address.Ipv4.sin_addr),
58
+ reinterpret_cast<const BYTE*>(&address.Ipv4.sin_addr) + sizeof(address.Ipv4.sin_addr),
59
+ std::begin(result.bytes));
60
+ }
61
+ else if (address.si_family == AF_INET6)
62
+ {
63
+ result.family = IpAddressFamily_V6;
64
+ std::copy(std::begin(address.Ipv6.sin6_addr.u.Byte), std::end(address.Ipv6.sin6_addr.u.Byte), std::begin(result.bytes));
65
+ }
66
+
67
+ return result;
68
+}
69
+
70
+std::vector<IpAddress> ToIpAddresses(const DnsInfo& dns)
71
+{
72
+ std::vector<IpAddress> result;
73
+ result.reserve(dns.Servers.size());
74
+ for (const auto& server : dns.Servers)
75
+ {
76
+ if (server.empty())
77
+ {
78
+ continue;
79
+ }
80
+
81
+ result.emplace_back(ToIpAddress(wsl::windows::common::string::StringToSockAddrInet(wsl::shared::string::MultiByteToWide(server))));
82
+ }
83
+
84
+ return result;
85
+}
86
+
87
+WslVirtioNetConfig BuildVirtioNetConfig(
88
+ const std::shared_ptr<NetworkSettings>& networkSettings, bool enableIpv6, std::optional<wsl::shared::string::MacAddress> clientMacAddress = {})
89
+{
90
+ ULONG netmask{};
91
+ if (networkSettings->PreferredIpAddress.Address.si_family == AF_INET)
92
+ {
93
+ LOG_IF_WIN32_ERROR(ConvertLengthToIpv4Mask(networkSettings->PreferredIpAddress.PrefixLength, &netmask));
94
+ }
95
+
96
+ WslVirtioNetConfig config{};
97
+ config.clientIp = ToIpv4Address(networkSettings->PreferredIpAddress.Address);
98
+ config.hasClientIpv6 = enableIpv6 && networkSettings->PreferredIpv6Address.Address.si_family == AF_INET6;
99
+ config.clientIpv6 = ToIpv6Address(networkSettings->PreferredIpv6Address.Address);
100
+ config.clientMac = ToEthernetAddress(clientMacAddress.value_or(c_defaultClientMacAddress));
101
+ config.gatewayIp = ToIpv4Address(networkSettings->GetBestGatewayAddress());
102
+ config.gatewayMac = ToEthernetAddress(c_gatewayMacAddress);
103
+ config.gatewayMacIpv6 = ToEthernetAddress(c_gatewayMacAddress);
104
+ config.netmask.value = netmask;
105
+ return config;
106
+}
107
+
108
+} // namespace
109
110
ConsommeNetworking::ConsommeNetworking(
18
- GnsChannel&& gnsChannel,
19
- ConsommeNetworkingFlags flags,
20
- LPCWSTR dnsOptions,
21
- std::shared_ptr<GuestDeviceManager> guestDeviceManager,
22
- wil::shared_handle userToken,
23
- std::wstring swiotlbConfig) :
111
+ GnsChannel&& gnsChannel, ConsommeNetworkingFlags flags, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
112
m_guestDeviceManager(std::move(guestDeviceManager)),
113
m_userToken(std::move(userToken)),
114
m_gnsChannel(std::move(gnsChannel)),
115
m_flags(flags),
28
- m_dnsOptions(dnsOptions),
29
- m_swiotlbOption(std::move(swiotlbConfig))
116
+ m_dnsOptions(dnsOptions)
117
{
118
}
119
@@ -159,38 +246,28 @@ uint16_t ConsommeNetworking::ModifyOpenPorts(
246
protocol);
247
248
auto lock = m_lock.lock_exclusive();
162
- const auto server = m_guestDeviceManager->GetRemoteFileSystem(VIRTIO_NET_CLASS_ID, c_defaultDeviceTag);
163
- THROW_HR_IF(E_UNEXPECTED, !server);
164
-
165
- const auto hostAddressStr = wsl::windows::common::string::SockAddrInetToString(hostAddress);
166
-
167
- std::wstring portString = std::format(L"tag={};guest_port={};listen_addr={}", tag, GuestPort, hostAddressStr.c_str());
168
-
169
- if (HostPort != WSLC_EPHEMERAL_PORT)
170
- {
171
- portString += std::format(L";host_port={}", HostPort);
172
- }
173
-
174
- if (!isOpen)
175
- {
176
- portString += L";allocate=false";
177
- }
178
-
179
- if (protocol == IPPROTO_UDP)
180
- {
181
- portString += L";udp";
182
- }
183
-
184
- const HRESULT addShareResult = server->AddShare(portString.c_str(), nullptr, 0);
185
- WSL_LOG("MapVirtioPort", TraceLoggingValue(portString.c_str(), "PortString"), TraceLoggingValue(addShareResult, "Result"));
249
+ const auto device = m_guestDeviceManager->GetVirtioNetDevice(tag);
250
+ const auto transportProtocol = (protocol == IPPROTO_UDP) ? TransportProtocol_Udp : TransportProtocol_Tcp;
251
+ auto listenAddress = ToIpAddress(hostAddress);
252
187
- if (HostPort == WSLC_EPHEMERAL_PORT && isOpen && SUCCEEDED(addShareResult))
253
+ if (isOpen)
254
{
189
- // For anonymous binds, the allocated host port is encoded in the return value.
190
- return static_cast<uint16_t>(addShareResult - S_OK);
255
+ UINT16 allocatedPort{};
256
+ THROW_IF_FAILED(device->BindPort(transportProtocol, &listenAddress, HostPort, GuestPort, &allocatedPort));
257
+ WSL_LOG(
258
+ "MapVirtioPort",
259
+ TraceLoggingValue(tag, "Tag"),
260
+ TraceLoggingValue(HostPort, "HostPort"),
261
+ TraceLoggingValue(GuestPort, "GuestPort"));
262
+ return allocatedPort;
263
}
264
193
- THROW_IF_FAILED_MSG(addShareResult, "Failed to set virtionet port mapping: %ls", portString.c_str());
265
+ THROW_IF_FAILED(device->UnbindPort(transportProtocol, listenAddress.family, GuestPort));
266
+ WSL_LOG(
267
+ "UnmapVirtioPort",
268
+ TraceLoggingValue(tag, "Tag"),
269
+ TraceLoggingValue(HostPort, "HostPort"),
270
+ TraceLoggingValue(GuestPort, "GuestPort"));
271
return HostPort;
272
}
273
@@ -224,29 +301,7 @@ void ConsommeNetworking::RefreshGuestConnection()
301
// Query current networking information before acquiring the lock.
302
auto networkSettings = GetHostEndpointSettings();
303
227
- std::wstring device_options;
228
- auto appendOption = [&device_options](std::wstring_view key, std::wstring_view value) {
229
- if (!value.empty())
230
- {
231
- std::format_to(std::back_inserter(device_options), L"{}{}={}", device_options.empty() ? L"" : L";", key, value);
232
- }
233
- };
234
-
235
- ULONG net_mask{};
236
- if (ConvertLengthToIpv4Mask(networkSettings->PreferredIpAddress.PrefixLength, &net_mask) == 0)
237
- {
238
- auto net_mask_string =
239
- std::format(L"{}.{}.{}.{}", net_mask & 0xFF, (net_mask >> 8) & 0xFF, (net_mask >> 16) & 0xFF, (net_mask >> 24) & 0xFF);
240
- appendOption(L"netmask", net_mask_string);
241
- }
242
-
243
- appendOption(L"client_ip", networkSettings->PreferredIpAddress.AddressString);
304
std::wstring default_route = networkSettings->GetBestGatewayAddressString();
245
- appendOption(L"gateway_ip", default_route);
246
- if (WI_IsFlagSet(m_flags, ConsommeNetworkingFlags::Ipv6))
247
- {
248
- appendOption(L"client_ip_ipv6", networkSettings->PreferredIpv6Address.AddressString);
249
- }
305
306
networking::DnsInfo currentDns{};
307
if (WI_IsFlagSet(m_flags, ConsommeNetworkingFlags::DnsTunneling))
@@ -261,36 +316,22 @@ void ConsommeNetworking::RefreshGuestConnection()
316
}
317
318
const auto minMtu = GetMinimumConnectedInterfaceMtu();
319
+ const auto virtioNetConfig = BuildVirtioNetConfig(networkSettings, WI_IsFlagSet(m_flags, ConsommeNetworkingFlags::Ipv6));
320
321
// Acquire the lock and perform device updates.
322
auto lock = m_lock.lock_exclusive();
323
268
- // Add virtio net adapter to guest. If the adapter already exists update adapter state.
269
- if (device_options != m_trackedDeviceOptions)
324
+ // Add virtio net adapter to guest. Subsequent address/route/DNS changes are sent through GNS notifications below.
325
+ if (!m_adapterId.has_value())
326
{
271
-
272
- WSL_LOG("RefreshVirtioNetConnection", TraceLoggingValue(device_options.c_str(), "DeviceOptions"));
273
- if (!m_adapterId.has_value())
274
- {
275
- m_adapterId = m_guestDeviceManager->AddGuestDevice(
276
- VIRTIO_NET_DEVICE_ID,
277
- VIRTIO_NET_CLASS_ID,
278
- c_eth0DeviceName,
279
- m_swiotlbOption.c_str(),
280
- device_options.c_str(),
281
- 0,
282
- m_userToken.get());
283
- }
284
- else
285
- {
286
- const auto server = m_guestDeviceManager->GetRemoteFileSystem(VIRTIO_NET_CLASS_ID, c_defaultDeviceTag);
287
- if (server)
288
- {
289
- LOG_IF_FAILED(server->AddSharePath(c_eth0DeviceName, device_options.c_str(), 0));
290
- }
291
- }
292
-
293
- m_trackedDeviceOptions = device_options;
327
+ WSL_LOG(
328
+ "RefreshVirtioNetConnection",
329
+ TraceLoggingValue(networkSettings->PreferredIpAddress.AddressString.c_str(), "ClientIp"),
330
+ TraceLoggingValue(networkSettings->PreferredIpAddress.PrefixLength, "PrefixLength"),
331
+ TraceLoggingValue(default_route.c_str(), "GatewayIp"),
332
+ TraceLoggingValue(networkSettings->PreferredIpv6Address.AddressString.c_str(), "ClientIpv6"));
333
+ m_adapterId =
334
+ m_guestDeviceManager->AddVirtioNetDevice(c_eth0DeviceName, virtioNetConfig, ToIpAddresses(currentDns), m_userToken.get());
335
}
336
337
UpdateIpv4Address(networkSettings->PreferredIpAddress);
@@ -309,27 +350,22 @@ void ConsommeNetworking::RefreshGuestConnection()
350
351
void ConsommeNetworking::SetupLoopbackDevice()
352
{
353
+ auto loopbackSettings = std::make_shared<NetworkSettings>();
354
const auto* clientIp = WI_IsFlagSet(m_flags, ConsommeNetworkingFlags::LoopbackClientIp) ? L"127.0.0.1" : L"169.254.73.250";
313
- const auto deviceOptions =
314
- std::format(L"client_ip={};client_mac=00:11:22:33:44:55;gateway_ip=169.254.73.249;netmask=255.255.255.248", clientIp);
315
-
316
- m_localhostAdapterId = m_guestDeviceManager->AddGuestDevice(
317
- VIRTIO_NET_DEVICE_ID,
318
- VIRTIO_NET_CLASS_ID,
319
- c_loopbackDeviceName,
320
- m_swiotlbOption.c_str(),
321
- deviceOptions.c_str(),
322
- 0,
323
- m_userToken.get());
324
-
325
- // The loopback gateway (see LX_INIT_IPV4_LOOPBACK_GATEWAY_ADDRESS) is 169.254.73.249, so assign loopback0 an
326
- // address of 169.254.73.153 with a netmask of 29 so that the only addresses associated with this adapter are
327
- // itself and the gateway.
355
+ loopbackSettings->PreferredIpAddress.Address = wsl::windows::common::string::StringToSockAddrInet(clientIp);
356
+ loopbackSettings->PreferredIpAddress.AddressString = clientIp;
357
+ loopbackSettings->PreferredIpAddress.PrefixLength = 28;
358
+ loopbackSettings->Routes.emplace(EndpointRoute::DefaultRoute(AF_INET, wsl::windows::common::string::StringToSockAddrInet(L"169.254.73.249")));
359
+ m_localhostAdapterId = m_guestDeviceManager->AddVirtioNetDevice(
360
+ c_loopbackDeviceName, BuildVirtioNetConfig(loopbackSettings, false, c_gatewayMacAddress), {}, m_userToken.get());
361
+
362
+ // The loopback gateway (see LX_INIT_IPV4_LOOPBACK_GATEWAY_ADDRESS) is 169.254.73.249, so use a /28 subnet
363
+ // that includes both the client and gateway addresses.
364
// N.B. The MAC address is advertised with the virtio device so doesn't need to be explicitly set.
365
hns::HNSEndpoint endpointProperties;
366
endpointProperties.ID = m_localhostAdapterId.value();
367
endpointProperties.IPAddress = L"169.254.73.250";
332
- endpointProperties.PrefixLength = 29;
368
+ endpointProperties.PrefixLength = 28;
369
endpointProperties.PortFriendlyName = c_loopbackDeviceName;
370
m_gnsChannel.SendEndpointState(endpointProperties);
371
src/windows/common/ConsommeNetworking.h
+1
-9
@@ -23,13 +23,7 @@ DEFINE_ENUM_FLAG_OPERATORS(ConsommeNetworkingFlags);
23
class ConsommeNetworking : public INetworkingEngine
24
{
25
public:
26
- ConsommeNetworking(
27
- GnsChannel&& gnsChannel,
28
- ConsommeNetworkingFlags flags,
29
- LPCWSTR dnsOptions,
30
- std::shared_ptr<GuestDeviceManager> guestDeviceManager,
31
- wil::shared_handle userToken,
32
- std::wstring swiotlbConfig);
26
+ ConsommeNetworking(GnsChannel&& gnsChannel, ConsommeNetworkingFlags flags, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
27
28
~ConsommeNetworking() override;
29
@@ -74,12 +68,10 @@ private:
68
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
69
ConsommeNetworkingFlags m_flags = ConsommeNetworkingFlags::None;
70
LPCWSTR m_dnsOptions = nullptr;
77
- std::wstring m_swiotlbOption;
71
std::optional<GUID> m_localhostAdapterId;
72
std::optional<GUID> m_adapterId;
73
74
ULONG m_networkMtu = 0;
82
- std::wstring m_trackedDeviceOptions;
75
networking::EndpointIpAddress m_trackedIpv4Address{};
76
networking::EndpointIpAddress m_trackedIpv6Address{};
77
std::wstring m_trackedDefaultRoute;
src/windows/common/DeviceHostProxy.cpp
+348
-14
@@ -2,6 +2,7 @@
2
3
#include "precomp.h"
4
#include "DeviceHostProxy.h"
5
+#include "WslSecurity.h"
6
7
// This template works around a limitation with decltype on overloaded functions. It will be able
8
// to get the correct version of GetVmWorkerProcess based on the provided type arguments. By
@@ -22,8 +23,18 @@ using GetVmWorkerProcessType = decltype(GetVmWorkerProcess(std::declval<Args>().
23
24
using namespace wsl::windows::common::hcs;
25
25
-DeviceHostProxy::DeviceHostProxy(const std::wstring& VmId, const GUID& RuntimeId) :
26
- m_systemId{VmId}, m_runtimeId{RuntimeId}, m_system{wsl::windows::common::hcs::OpenComputeSystem(VmId.c_str(), GENERIC_ALL)}, m_shutdown{false}
26
+namespace {
27
+constexpr GUID c_virtioFsDeviceId{0x872270E1, 0xA899, 0x4AF6, {0xB4, 0x54, 0x71, 0x93, 0x63, 0x44, 0x35, 0xAD}};
28
+constexpr GUID c_virtioNetDeviceId{0xF07010D0, 0x0EA9, 0x447F, {0x88, 0xEF, 0xBD, 0x95, 0x2A, 0x4D, 0x2F, 0x14}};
29
+constexpr GUID c_virtioPmemDeviceId{0xEDBB24BB, 0x5E19, 0x40F4, {0x8A, 0x0F, 0x82, 0x24, 0x31, 0x30, 0x64, 0xFD}};
30
+} // namespace
31
+
32
+DeviceHostProxy::DeviceHostProxy(const std::wstring& VmId, const GUID& RuntimeId, bool EnableTelemetry) :
33
+ m_systemId{VmId},
34
+ m_runtimeId{RuntimeId},
35
+ m_enableTelemetry{EnableTelemetry},
36
+ m_system{wsl::windows::common::hcs::OpenComputeSystem(VmId.c_str(), GENERIC_ALL)},
37
+ m_shutdown{false}
38
{
39
m_devicesShutdown = false;
40
m_git = wil::CoCreateInstance<IGlobalInterfaceTable>(CLSID_StdGlobalInterfaceTable, CLSCTX_INPROC_SERVER);
@@ -31,6 +42,8 @@ DeviceHostProxy::DeviceHostProxy(const std::wstring& VmId, const GUID& RuntimeId
42
43
GUID DeviceHostProxy::AddNewDevice(const GUID& Type, const wil::com_ptr<IPlan9FileSystem>& Plan9Fs, const std::wstring& VirtIoTag)
44
{
45
+ std::lock_guard lifecycleLock(m_deviceLifecycleLock);
46
+
47
const wrl::ComPtr<IUnknown> thisUnknown{CastToUnknown()};
48
GUID instanceId{};
49
THROW_IF_FAILED(UuidCreate(&instanceId));
@@ -45,7 +58,7 @@ GUID DeviceHostProxy::AddNewDevice(const GUID& Type, const wil::com_ptr<IPlan9Fi
58
auto lock = m_devicesLock.lock_exclusive();
59
THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
60
48
- m_devices.emplace(instanceId, DeviceHostProxyEntry{});
61
+ m_devices.emplace(instanceId, DeviceHostProxyEntry{.Type = Type});
62
}
63
64
auto removeOnFailure = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
@@ -54,24 +67,180 @@ GUID DeviceHostProxy::AddNewDevice(const GUID& Type, const wil::com_ptr<IPlan9Fi
67
});
68
69
// Add the device to the compute system on behalf of the device host.
70
+ AddFlexibleIoDevice(Type, instanceId);
71
+ removeOnFailure.release();
72
+ return instanceId;
73
+}
74
+
75
+GUID DeviceHostProxy::AddVirtioNetDevice(_In_ HANDLE UserToken, const WslVirtioNetConfig& Config, const std::vector<IpAddress>& Nameservers)
76
+{
77
+ std::lock_guard lifecycleLock(m_deviceLifecycleLock);
78
+
79
+ GUID instanceId{};
80
+ THROW_IF_FAILED(UuidCreate(&instanceId));
81
+
82
+ {
83
+ auto lock = m_devicesLock.lock_exclusive();
84
+ THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
85
+ m_devices.emplace(instanceId, DeviceHostProxyEntry{.Type = c_virtioNetDeviceId});
86
+ }
87
+
88
+ wil::com_ptr<IUnknown> device;
89
+ auto removeOnFailure = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
90
+ TeardownDevice(device);
91
+ auto lock = m_devicesLock.lock_exclusive();
92
+ m_devices.erase(instanceId);
93
+ });
94
+ wil::com_ptr<IWslVirtioNetDevice> netDevice;
95
+ {
96
+ auto instanceIdForCall = instanceId;
97
+ auto config = Config;
98
+ auto nameservers = Nameservers;
99
+ IpAddress emptyNameserver{};
100
+ auto* nameserversData = nameservers.empty() ? &emptyNameserver : nameservers.data();
101
+ THROW_IF_FAILED(GetWslVm(UserToken)->CreateVirtioNetDevice(
102
+ &instanceIdForCall,
103
+ GetCallback().get(),
104
+ &config,
105
+ gsl::narrow_cast<UINT32>(nameservers.size()),
106
+ nameserversData,
107
+ netDevice.put()));
108
+ }
109
+ device = netDevice.query<IUnknown>();
110
+
111
+ {
112
+ auto lock = m_devicesLock.lock_exclusive();
113
+ const auto entry = m_devices.find(instanceId);
114
+ THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown || entry == m_devices.end());
115
+ entry->second.Device = device;
116
+ }
117
+
118
+ AddFlexibleIoDevice(c_virtioNetDeviceId, instanceId);
119
+ removeOnFailure.release();
120
+ return instanceId;
121
+}
122
+
123
+GUID DeviceHostProxy::AddVirtiofsDevice(
124
+ _In_ HANDLE UserToken, const std::wstring& Label, const std::wstring& RootPath, VirtiofsShareKind Kind, UINT32 ShmemSizeMb, const std::wstring& MountOptions)
125
+{
126
+ std::lock_guard lifecycleLock(m_deviceLifecycleLock);
127
+
128
+ GUID instanceId{};
129
+ THROW_IF_FAILED(UuidCreate(&instanceId));
130
+
131
+ {
132
+ auto lock = m_devicesLock.lock_exclusive();
133
+ THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
134
+ m_devices.emplace(instanceId, DeviceHostProxyEntry{.Type = c_virtioFsDeviceId});
135
+ }
136
+
137
+ wil::com_ptr<IUnknown> device;
138
+ auto removeOnFailure = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
139
+ TeardownDevice(device);
140
+ auto lock = m_devicesLock.lock_exclusive();
141
+ m_devices.erase(instanceId);
142
+ });
143
+ wil::com_ptr<IWslVirtiofsDevice> virtiofsDevice;
144
+ {
145
+ auto instanceIdForCall = instanceId;
146
+ const auto label = wil::make_bstr(Label.c_str());
147
+ const auto rootPath = wil::make_bstr(RootPath.c_str());
148
+ const auto mountOptions = wil::make_bstr(MountOptions.c_str());
149
+ WslVirtiofsConfig config{
150
+ .label = label.get(),
151
+ .rootPath = rootPath.get(),
152
+ .kind = Kind,
153
+ .shmemSizeMb = ShmemSizeMb,
154
+ // To workaround memory aperture limitations, limit virtiofs devices to one queue.
155
+ .queueCount = 1,
156
+ .mountOptions = mountOptions.get()};
157
+ THROW_IF_FAILED(GetWslVm(UserToken)->CreateVirtiofsDevice(&instanceIdForCall, GetCallback().get(), &config, virtiofsDevice.put()));
158
+ }
159
+ device = virtiofsDevice.query<IUnknown>();
160
+
161
+ {
162
+ auto lock = m_devicesLock.lock_exclusive();
163
+ const auto entry = m_devices.find(instanceId);
164
+ THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown || entry == m_devices.end());
165
+ entry->second.Device = device;
166
+ }
167
+
168
+ AddFlexibleIoDevice(c_virtioFsDeviceId, instanceId);
169
+ removeOnFailure.release();
170
+ return instanceId;
171
+}
172
+
173
+GUID DeviceHostProxy::AddVirtioPmemDevice(_In_ HANDLE UserToken, const std::wstring& Path, bool Writable)
174
+{
175
+ std::lock_guard lifecycleLock(m_deviceLifecycleLock);
176
+
177
+ GUID instanceId{};
178
+ THROW_IF_FAILED(UuidCreate(&instanceId));
179
+
180
+ {
181
+ auto lock = m_devicesLock.lock_exclusive();
182
+ THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
183
+ m_devices.emplace(instanceId, DeviceHostProxyEntry{.Type = c_virtioPmemDeviceId});
184
+ }
185
+
186
+ wil::com_ptr<IUnknown> device;
187
+ auto removeOnFailure = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
188
+ TeardownDevice(device);
189
+ auto lock = m_devicesLock.lock_exclusive();
190
+ m_devices.erase(instanceId);
191
+ });
192
+ wil::com_ptr<IWslVirtioPmemDevice> pmemDevice;
193
+ {
194
+ auto instanceIdForCall = instanceId;
195
+ const auto path = wil::make_bstr(Path.c_str());
196
+ WslVirtioPmemConfig config{.path = path.get(), .writable = Writable};
197
+ THROW_IF_FAILED(GetWslVm(UserToken)->CreateVirtioPmemDevice(&instanceIdForCall, GetCallback().get(), &config, pmemDevice.put()));
198
+ }
199
+ device = pmemDevice.query<IUnknown>();
200
+
201
+ {
202
+ auto lock = m_devicesLock.lock_exclusive();
203
+ const auto entry = m_devices.find(instanceId);
204
+ THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown || entry == m_devices.end());
205
+ entry->second.Device = device;
206
+ }
207
+
208
+ AddFlexibleIoDevice(c_virtioPmemDeviceId, instanceId);
209
+ removeOnFailure.release();
210
+ return instanceId;
211
+}
212
+
213
+void DeviceHostProxy::AddFlexibleIoDevice(const GUID& Type, const GUID& InstanceId)
214
+{
215
ModifySettingRequest<FlexibleIoDevice> request;
216
request.RequestType = ModifyRequestType::Add;
217
request.ResourcePath = L"VirtualMachine/Devices/FlexibleIov/";
60
- request.ResourcePath += wsl::shared::string::GuidToString<wchar_t>(instanceId, wsl::shared::string::GuidToStringFlags::None);
218
+ request.ResourcePath += wsl::shared::string::GuidToString<wchar_t>(InstanceId, wsl::shared::string::GuidToStringFlags::None);
219
request.Settings.EmulatorId = Type;
220
request.Settings.HostingModel = FlexibleIoDeviceHostingModel::ExternalRestricted;
221
wsl::windows::common::hcs::ModifyComputeSystem(m_system.get(), wsl::shared::ToJsonW(request).c_str());
64
- removeOnFailure.release();
65
- return instanceId;
222
}
223
68
-void DeviceHostProxy::RemoveDevice(const GUID& Type, const GUID& InstanceId)
224
+void DeviceHostProxy::RemoveDevice(const GUID& InstanceId)
225
{
226
+ std::lock_guard lifecycleLock(m_deviceLifecycleLock);
227
+ wil::com_ptr<IUnknown> device;
228
+ GUID type{};
229
+
230
{
231
auto lock = m_devicesLock.lock_exclusive();
232
+ const auto entry = m_devices.find(InstanceId);
233
THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
73
- THROW_HR_IF(E_INVALIDARG, m_devices.find(InstanceId) == m_devices.end());
234
+ THROW_HR_IF(E_INVALIDARG, entry == m_devices.end());
235
+ entry->second.ShuttingDown = true;
236
+ device = entry->second.Device;
237
+ type = entry->second.Type;
238
+ }
239
240
+ TeardownDevice(device);
241
+
242
+ {
243
+ auto lock = m_devicesLock.lock_exclusive();
244
m_devices.erase(InstanceId);
245
}
246
@@ -82,7 +251,7 @@ void DeviceHostProxy::RemoveDevice(const GUID& Type, const GUID& InstanceId)
251
request.RequestType = ModifyRequestType::Remove;
252
request.ResourcePath = L"VirtualMachine/Devices/FlexibleIov/";
253
request.ResourcePath += wsl::shared::string::GuidToString<wchar_t>(InstanceId, wsl::shared::string::GuidToStringFlags::None);
85
- request.Settings.EmulatorId = Type;
254
+ request.Settings.EmulatorId = type;
255
request.Settings.HostingModel = FlexibleIoDeviceHostingModel::ExternalRestricted;
256
wsl::windows::common::hcs::ModifyComputeSystem(m_system.get(), wsl::shared::ToJsonW(request).c_str());
257
}
@@ -125,18 +294,139 @@ wil::com_ptr<IPlan9FileSystem> DeviceHostProxy::GetRemoteFileSystem(const GUID&
294
return {};
295
}
296
297
+wil::com_ptr<IWslVirtioNetDevice> DeviceHostProxy::GetVirtioNetDevice(const GUID& InstanceId)
298
+{
299
+ auto lock = m_devicesLock.lock_shared();
300
+ THROW_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
301
+
302
+ const auto device = m_devices.find(InstanceId);
303
+ THROW_HR_IF(E_NOT_SET, device == m_devices.end() || device->second.ShuttingDown || !device->second.Device);
304
+ return device->second.Device.query<IWslVirtioNetDevice>();
305
+}
306
+
307
+void DeviceHostProxy::SetSwiotlb(UINT64 GpaBase, UINT64 SizeBytes)
308
+{
309
+ if (GpaBase == 0 && SizeBytes == 0)
310
+ {
311
+ return;
312
+ }
313
+
314
+ auto lock = m_lock.lock_exclusive();
315
+ THROW_HR_IF(E_CHANGED_STATE, m_shutdown);
316
+
317
+ SwiotlbConfig config{.gpaBase = GpaBase, .sizeBytes = SizeBytes};
318
+ if (m_swiotlbConfigured)
319
+ {
320
+ THROW_HR_IF(
321
+ HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS),
322
+ m_swiotlbConfig.gpaBase != config.gpaBase || m_swiotlbConfig.sizeBytes != config.sizeBytes);
323
+ }
324
+ else
325
+ {
326
+ m_swiotlbConfig = config;
327
+ m_swiotlbConfigured = true;
328
+ }
329
+
330
+ ConfigureSwiotlb(m_wslVm, m_wslVmSwiotlbConfigured);
331
+ ConfigureSwiotlb(m_adminWslVm, m_adminWslVmSwiotlbConfigured);
332
+}
333
+
334
void DeviceHostProxy::Shutdown()
335
{
336
+ std::lock_guard lifecycleLock(m_deviceLifecycleLock);
337
+
338
{
339
auto lock = m_lock.lock_exclusive();
340
m_fileSystems.clear();
341
m_shutdown = true;
342
}
343
344
+ std::vector<wil::com_ptr<IUnknown>> devices;
345
{
346
auto lock = m_devicesLock.lock_exclusive();
138
- m_devices.clear();
347
+
348
+ // Block device retrieval and new registrations while retaining the entries needed by
349
+ // Teardown() callbacks to unregister doorbells and destroy mapped ranges.
350
m_devicesShutdown = true;
351
+ devices.reserve(m_devices.size());
352
+ for (auto& device : m_devices)
353
+ {
354
+ device.second.ShuttingDown = true;
355
+ devices.emplace_back(device.second.Device);
356
+ }
357
+ }
358
+
359
+ for (const auto& device : devices)
360
+ {
361
+ TeardownDevice(device);
362
+ }
363
+
364
+ {
365
+ auto lock = m_devicesLock.lock_exclusive();
366
+ m_devices.clear();
367
+ }
368
+}
369
+
370
+wil::com_ptr<IWslVm> DeviceHostProxy::GetWslVm(_In_ HANDLE UserToken)
371
+{
372
+ auto lock = m_lock.lock_exclusive();
373
+ THROW_HR_IF(E_CHANGED_STATE, m_shutdown);
374
+
375
+ const auto elevated = wsl::windows::common::security::IsTokenElevated(UserToken);
376
+ auto& cachedVm = elevated ? m_adminWslVm : m_wslVm;
377
+ auto& swiotlbConfigured = elevated ? m_adminWslVmSwiotlbConfigured : m_wslVmSwiotlbConfigured;
378
+ if (!cachedVm)
379
+ {
380
+ auto revert = wil::impersonate_token(UserToken);
381
+ const auto& clsid = m_enableTelemetry
382
+ ? (elevated ? CLSID_WSL_DEVICE_HOST_ADMIN : CLSID_WSL_DEVICE_HOST)
383
+ : (elevated ? CLSID_WSL_DEVICE_HOST_NO_TELEMETRY_ADMIN : CLSID_WSL_DEVICE_HOST_NO_TELEMETRY);
384
+ const auto host = wil::CoCreateInstance<IWslDeviceHost>(clsid, CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA);
385
+ auto vmId = m_runtimeId;
386
+ wil::com_ptr<IWslVm> vm;
387
+ THROW_IF_FAILED(host->OpenVm(&vmId, vm.put()));
388
+ cachedVm = std::move(vm);
389
+ }
390
+
391
+ ConfigureSwiotlb(cachedVm, swiotlbConfigured);
392
+ return cachedVm;
393
+}
394
+
395
+_Requires_lock_held_(m_lock)
396
+void DeviceHostProxy::ConfigureSwiotlb(const wil::com_ptr<IWslVm>& Vm, bool& Configured)
397
+{
398
+ if (Vm && m_swiotlbConfigured && !Configured)
399
+ {
400
+ THROW_IF_FAILED(Vm->SetSwiotlb(&m_swiotlbConfig));
401
+ Configured = true;
402
+ }
403
+}
404
+
405
+wil::com_ptr<IWslDeviceHostCallback> DeviceHostProxy::GetCallback()
406
+{
407
+ wil::com_ptr<IWslDeviceHostCallback> callback;
408
+ THROW_IF_FAILED(CastToUnknown()->QueryInterface(IID_PPV_ARGS(callback.put())));
409
+ return callback;
410
+}
411
+
412
+void DeviceHostProxy::TeardownDevice(const wil::com_ptr<IUnknown>& Device) noexcept
413
+{
414
+ if (!Device)
415
+ {
416
+ return;
417
+ }
418
+
419
+ if (const auto netDevice = Device.try_query<IWslVirtioNetDevice>())
420
+ {
421
+ LOG_IF_FAILED(netDevice->Teardown());
422
+ }
423
+ else if (const auto virtiofsDevice = Device.try_query<IWslVirtiofsDevice>())
424
+ {
425
+ LOG_IF_FAILED(virtiofsDevice->Teardown());
426
+ }
427
+ else if (const auto pmemDevice = Device.try_query<IWslVirtioPmemDevice>())
428
+ {
429
+ LOG_IF_FAILED(pmemDevice->Teardown());
430
}
431
}
432
@@ -199,6 +489,17 @@ CATCH_RETURN()
489
490
HRESULT
491
DeviceHostProxy::RegisterDoorbell(const GUID& InstanceId, UINT8 BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags, HANDLE Event)
492
+{
493
+ return RegisterDoorbellImpl(InstanceId, BarIndex, Offset, TriggerValue, Flags, Event);
494
+}
495
+
496
+HRESULT
497
+DeviceHostProxy::RegisterDoorbell(GUID InstanceId, BYTE BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags, HANDLE Event)
498
+{
499
+ return RegisterDoorbellImpl(InstanceId, BarIndex, Offset, TriggerValue, Flags, Event);
500
+}
501
+
502
+HRESULT DeviceHostProxy::RegisterDoorbellImpl(const GUID& InstanceId, UINT8 BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags, HANDLE Event) noexcept
503
try
504
{
505
auto lock = m_devicesLock.lock_exclusive();
@@ -209,7 +510,7 @@ try
510
// N.B. For security it is enforced that each device can only register a small number of doorbells.
511
// Currently virtio-9p only uses one and the external virtio device uses two.
512
const auto knownDevice = m_devices.find(InstanceId);
212
- RETURN_HR_IF(E_ACCESSDENIED, knownDevice == m_devices.end() || knownDevice->second.DoorbellCount == DEVICE_HOST_PROXY_DOORBELL_LIMIT);
513
+ RETURN_HR_IF(E_ACCESSDENIED, knownDevice == m_devices.end() || knownDevice->second.ShuttingDown || knownDevice->second.DoorbellCount == DEVICE_HOST_PROXY_DOORBELL_LIMIT);
514
515
if (!knownDevice->second.MemoryNotification)
516
{
@@ -245,10 +546,20 @@ CATCH_RETURN()
546
547
HRESULT
548
DeviceHostProxy::UnregisterDoorbell(const GUID& InstanceId, UINT8 BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags)
549
+{
550
+ return UnregisterDoorbellImpl(InstanceId, BarIndex, Offset, TriggerValue, Flags);
551
+}
552
+
553
+HRESULT
554
+DeviceHostProxy::UnregisterDoorbell(GUID InstanceId, BYTE BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags)
555
+{
556
+ return UnregisterDoorbellImpl(InstanceId, BarIndex, Offset, TriggerValue, Flags);
557
+}
558
+
559
+HRESULT DeviceHostProxy::UnregisterDoorbellImpl(const GUID& InstanceId, UINT8 BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags) noexcept
560
try
561
{
562
auto lock = m_devicesLock.lock_exclusive();
251
- RETURN_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
563
564
// Check if the device is a known device and has registered a doorbell.
565
// N.B. If the device is being removed, the device can't be retrieved from the worker process
@@ -269,6 +580,19 @@ CATCH_RETURN()
580
HRESULT
581
DeviceHostProxy::CreateSectionBackedMmioRange(
582
const GUID& InstanceId, UINT8 BarIndex, UINT64 BarOffsetInPages, UINT64 PageCount, UINT64 MappingFlags, HANDLE SectionHandle, UINT64 SectionOffsetInPages)
583
+{
584
+ return CreateSectionBackedMmioRangeImpl(InstanceId, BarIndex, BarOffsetInPages, PageCount, MappingFlags, SectionHandle, SectionOffsetInPages);
585
+}
586
+
587
+HRESULT
588
+DeviceHostProxy::CreateSectionBackedMmioRange(
589
+ GUID InstanceId, BYTE BarIndex, UINT64 BarOffsetInPages, UINT64 PageCount, UINT64 MappingFlags, HANDLE SectionHandle, UINT64 SectionOffsetInPages)
590
+{
591
+ return CreateSectionBackedMmioRangeImpl(InstanceId, BarIndex, BarOffsetInPages, PageCount, MappingFlags, SectionHandle, SectionOffsetInPages);
592
+}
593
+
594
+HRESULT DeviceHostProxy::CreateSectionBackedMmioRangeImpl(
595
+ const GUID& InstanceId, UINT8 BarIndex, UINT64 BarOffsetInPages, UINT64 PageCount, UINT64 MappingFlags, HANDLE SectionHandle, UINT64 SectionOffsetInPages) noexcept
596
try
597
{
598
auto lock = m_devicesLock.lock_exclusive();
@@ -276,7 +600,7 @@ try
600
601
// Check if the device is one of the known devices.
602
const auto knownDevice = m_devices.find(InstanceId);
279
- THROW_HR_IF(E_ACCESSDENIED, knownDevice == m_devices.end());
603
+ THROW_HR_IF(E_ACCESSDENIED, knownDevice == m_devices.end() || knownDevice->second.ShuttingDown);
604
605
if (!knownDevice->second.MemoryMapping)
606
{
@@ -305,10 +629,20 @@ CATCH_RETURN()
629
630
HRESULT
631
DeviceHostProxy::DestroySectionBackedMmioRange(const GUID& InstanceId, UINT8 BarIndex, UINT64 BarOffsetInPages)
632
+{
633
+ return DestroySectionBackedMmioRangeImpl(InstanceId, BarIndex, BarOffsetInPages);
634
+}
635
+
636
+HRESULT
637
+DeviceHostProxy::DestroySectionBackedMmioRange(GUID InstanceId, BYTE BarIndex, UINT64 BarOffsetInPages)
638
+{
639
+ return DestroySectionBackedMmioRangeImpl(InstanceId, BarIndex, BarOffsetInPages);
640
+}
641
+
642
+HRESULT DeviceHostProxy::DestroySectionBackedMmioRangeImpl(const GUID& InstanceId, UINT8 BarIndex, UINT64 BarOffsetInPages) noexcept
643
try
644
{
645
auto lock = m_devicesLock.lock_exclusive();
311
- RETURN_HR_IF(E_CHANGED_STATE, m_devicesShutdown);
646
const auto device = m_devices.find(InstanceId);
647
RETURN_HR_IF(E_ACCESSDENIED, device == m_devices.end() || !device->second.MemoryMapping);
648
RETURN_IF_FAILED(device->second.MemoryMapping->DestroySectionBackedMmioRange(static_cast<FIOV_BAR_SELECTOR>(BarIndex), BarOffsetInPages));
src/windows/common/DeviceHostProxy.h
+54
-3
@@ -3,23 +3,36 @@
3
#pragma once
4
5
#include <windowsdefs.h>
6
+#include <WslDeviceHost.h>
7
#include "hcs.hpp"
8
9
namespace wrl = Microsoft::WRL;
10
10
-class DeviceHostProxy : public wrl::RuntimeClass<wrl::RuntimeClassFlags<wrl::RuntimeClassType::ClassicCom>, IVmDeviceHostSupport, IPlan9FileSystemHost>
11
+class DeviceHostProxy
12
+ : public wrl::RuntimeClass<wrl::RuntimeClassFlags<wrl::RuntimeClassType::ClassicCom>, IVmDeviceHostSupport, IPlan9FileSystemHost, IWslDeviceHostCallback>
13
{
14
public:
13
- DeviceHostProxy(const std::wstring& VmId, const GUID& RuntimeId);
15
+ DeviceHostProxy(const std::wstring& VmId, const GUID& RuntimeId, bool EnableTelemetry = true);
16
17
GUID AddNewDevice(const GUID& Type, const wil::com_ptr<IPlan9FileSystem>& Plan9Fs, const std::wstring& VirtIoTag);
18
17
- void RemoveDevice(const GUID& Type, const GUID& InstanceId);
19
+ GUID AddVirtioNetDevice(_In_ HANDLE UserToken, const WslVirtioNetConfig& Config, const std::vector<IpAddress>& Nameservers);
20
+
21
+ GUID AddVirtiofsDevice(
22
+ _In_ HANDLE UserToken, const std::wstring& Label, const std::wstring& RootPath, VirtiofsShareKind Kind, UINT32 ShmemSizeMb, const std::wstring& MountOptions);
23
+
24
+ GUID AddVirtioPmemDevice(_In_ HANDLE UserToken, const std::wstring& Path, bool Writable);
25
+
26
+ void RemoveDevice(const GUID& InstanceId);
27
28
void AddRemoteFileSystem(const GUID& ImplementationClsid, const std::wstring& Tag, const wil::com_ptr<IPlan9FileSystem>& Plan9Fs);
29
30
wil::com_ptr<IPlan9FileSystem> GetRemoteFileSystem(const GUID& ImplementationClsid, std::wstring_view Tag);
31
32
+ wil::com_ptr<IWslVirtioNetDevice> GetVirtioNetDevice(const GUID& InstanceId);
33
+
34
+ void SetSwiotlb(UINT64 GpaBase, UINT64 SizeBytes);
35
+
36
void Shutdown();
37
38
//
@@ -41,6 +54,18 @@ public:
54
55
IFACEMETHOD(DestroySectionBackedMmioRange)(const GUID& InstanceId, UINT8 BarIndex, UINT64 BarOffsetInPages) override;
56
57
+ //
58
+ // IWslDeviceHostCallback
59
+ //
60
+ IFACEMETHOD(RegisterDoorbell)(GUID InstanceId, BYTE BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags, HANDLE Event) override;
61
+
62
+ IFACEMETHOD(UnregisterDoorbell)(GUID InstanceId, BYTE BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags) override;
63
+
64
+ IFACEMETHOD(CreateSectionBackedMmioRange)(
65
+ GUID InstanceId, BYTE BarIndex, UINT64 BarOffsetInPages, UINT64 PageCount, UINT64 MappingFlags, HANDLE SectionHandle, UINT64 SectionOffsetInPages) override;
66
+
67
+ IFACEMETHOD(DestroySectionBackedMmioRange)(GUID InstanceId, BYTE BarIndex, UINT64 BarOffsetInPages) override;
68
+
69
private:
70
struct RemoteFileSystemInfo
71
{
@@ -95,21 +120,47 @@ private:
120
121
wil::com_ptr<IGlobalInterfaceTable> m_git;
122
123
+ struct DeviceHostProxyEntry;
124
+
125
+ wil::com_ptr<IWslVm> GetWslVm(_In_ HANDLE UserToken);
126
+ wil::com_ptr<IWslDeviceHostCallback> GetCallback();
127
+ void AddFlexibleIoDevice(const GUID& Type, const GUID& InstanceId);
128
+ _Requires_lock_held_(m_lock)
129
+ void ConfigureSwiotlb(const wil::com_ptr<IWslVm>& Vm, bool& Configured);
130
+ void TeardownDevice(const wil::com_ptr<IUnknown>& Device) noexcept;
131
+
132
+ HRESULT RegisterDoorbellImpl(const GUID& InstanceId, UINT8 BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags, HANDLE Event) noexcept;
133
+ HRESULT UnregisterDoorbellImpl(const GUID& InstanceId, UINT8 BarIndex, UINT64 Offset, UINT64 TriggerValue, UINT64 Flags) noexcept;
134
+ HRESULT CreateSectionBackedMmioRangeImpl(
135
+ const GUID& InstanceId, UINT8 BarIndex, UINT64 BarOffsetInPages, UINT64 PageCount, UINT64 MappingFlags, HANDLE SectionHandle, UINT64 SectionOffsetInPages) noexcept;
136
+ HRESULT DestroySectionBackedMmioRangeImpl(const GUID& InstanceId, UINT8 BarIndex, UINT64 BarOffsetInPages) noexcept;
137
+
138
std::wstring m_systemId;
139
GUID m_runtimeId;
140
+ bool m_enableTelemetry;
141
wsl::windows::common::hcs::unique_hcs_system m_system;
142
wil::srwlock m_lock;
143
std::vector<RemoteFileSystemInfo> m_fileSystems;
144
bool m_shutdown;
145
+ wil::com_ptr<IWslVm> m_wslVm;
146
+ wil::com_ptr<IWslVm> m_adminWslVm;
147
+ SwiotlbConfig m_swiotlbConfig{};
148
+ bool m_swiotlbConfigured = false;
149
+ bool m_wslVmSwiotlbConfigured = false;
150
+ bool m_adminWslVmSwiotlbConfigured = false;
151
152
struct DeviceHostProxyEntry
153
{
154
+ GUID Type{};
155
wil::com_ptr<IVmFiovGuestMemoryFastNotification> MemoryNotification;
156
wil::com_ptr<IVmFiovGuestMmioMappings> MemoryMapping;
157
+ wil::com_ptr<IUnknown> Device;
158
size_t DoorbellCount = 0;
159
+ bool ShuttingDown = false;
160
};
161
162
wil::com_ptr<IVmVirtualDeviceAccess> m_deviceAccess;
163
+ std::mutex m_deviceLifecycleLock;
164
wil::srwlock m_devicesLock;
165
std::map<GUID, DeviceHostProxyEntry, wsl::windows::common::helpers::GuidLess> m_devices;
166
bool m_devicesShutdown;
src/windows/common/GuestDeviceManager.cpp
+45
-47
@@ -4,8 +4,8 @@
4
#include "GuestDeviceManager.h"
5
#include "DeviceHostProxy.h"
6
7
-GuestDeviceManager::GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId) :
8
- m_machineId(machineId), m_deviceHostSupport(wil::MakeOrThrow<DeviceHostProxy>(machineId, runtimeId))
7
+GuestDeviceManager::GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId, bool EnableTelemetry) :
8
+ m_machineId(machineId), m_deviceHostSupport(wil::MakeOrThrow<DeviceHostProxy>(machineId, runtimeId, EnableTelemetry))
9
{
10
}
11
@@ -19,47 +19,18 @@ GuestDeviceManager::~GuestDeviceManager()
19
}
20
21
_Requires_lock_not_held_(m_lock)
22
-GUID GuestDeviceManager::AddGuestDevice(
23
- _In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Options, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
22
+GUID GuestDeviceManager::AddVirtiofsDevice(_In_ PCWSTR Label, _In_opt_ PCWSTR MountOptions, _In_ PCWSTR RootPath, _In_ HANDLE UserToken, VirtioFsShareOptions Options)
23
{
24
auto guestDeviceLock = m_lock.lock_exclusive();
26
- return AddHdvShareWithOptions(DeviceId, ImplementationClsid, AccessName, Options, Path, Flags, UserToken);
25
+ return m_deviceHostSupport->AddVirtiofsDevice(
26
+ UserToken, Label, RootPath, Options.Kind, Options.SharedMemorySizeMb, MountOptions ? MountOptions : L"");
27
}
28
29
-_Requires_lock_held_(m_lock)
30
-GUID GuestDeviceManager::AddHdvShareWithOptions(
31
- _In_ const GUID& DeviceId, _In_ const GUID& ImplementationClsid, _In_ PCWSTR AccessName, _In_opt_ PCWSTR Options, _In_ PCWSTR Path, _In_ UINT32 Flags, _In_ HANDLE UserToken)
29
+_Requires_lock_not_held_(m_lock)
30
+GUID GuestDeviceManager::AddVirtioPmemDevice(_In_ PCWSTR Path, bool ReadOnly, _In_ HANDLE UserToken)
31
{
33
- wil::com_ptr<IPlan9FileSystem> server;
34
-
35
- // Options are appended to the name with a semi-colon separator.
36
- // "name;key1=value1;key2=value2"
37
- // The AddSharePath implementation is responsible for separating them out and interpreting them.
38
- // N.B. A ";vm_id=<guid>" option is always appended so the device host can identify the owning VM.
39
- std::wstring nameWithOptions{AccessName};
40
- if (ARGUMENT_PRESENT(Options) && Options[0] != L'\0')
41
- {
42
- nameWithOptions += L";";
43
- nameWithOptions += Options;
44
- }
45
-
46
- nameWithOptions += std::format(L";vm_id={}", m_machineId);
47
-
48
- {
49
- auto revert = wil::impersonate_token(UserToken);
50
-
51
- server = GetRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag);
52
- if (!server)
53
- {
54
- server = wil::CoCreateInstance<IPlan9FileSystem>(ImplementationClsid, (CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING | CLSCTX_ENABLE_AAA));
55
- m_deviceHostSupport->AddRemoteFileSystem(ImplementationClsid, c_defaultDeviceTag.c_str(), server);
56
- }
57
-
58
- THROW_IF_FAILED(server->AddSharePath(nameWithOptions.c_str(), Path, Flags));
59
- }
60
-
61
- // This requires more privileges than the user may have, so impersonation is disabled.
62
- return m_deviceHostSupport->AddNewDevice(DeviceId, server, AccessName);
32
+ auto guestDeviceLock = m_lock.lock_exclusive();
33
+ return m_deviceHostSupport->AddVirtioPmemDevice(UserToken, Path, !ReadOnly);
34
}
35
36
_Requires_lock_not_held_(m_lock)
@@ -69,22 +40,35 @@ GUID GuestDeviceManager::AddNewDevice(_In_ const GUID& deviceId, _In_ const wil:
40
return m_deviceHostSupport->AddNewDevice(deviceId, server, tag);
41
}
42
43
+GUID GuestDeviceManager::AddVirtioNetDevice(_In_ PCWSTR Tag, const WslVirtioNetConfig& Config, const std::vector<IpAddress>& Nameservers, _In_ HANDLE UserToken)
44
+{
45
+ auto guestDeviceLock = m_lock.lock_exclusive();
46
+ THROW_HR_IF(E_INVALIDARG, m_virtioNetDevices.contains(Tag));
47
+ const auto instanceId = m_deviceHostSupport->AddVirtioNetDevice(UserToken, Config, Nameservers);
48
+ m_virtioNetDevices.emplace(Tag, instanceId);
49
+ return instanceId;
50
+}
51
+
52
+wil::com_ptr<IWslVirtioNetDevice> GuestDeviceManager::GetVirtioNetDevice(_In_ PCWSTR Tag)
53
+{
54
+ auto guestDeviceLock = m_lock.lock_shared();
55
+ const auto device = m_virtioNetDevices.find(Tag);
56
+ THROW_HR_IF(E_NOT_SET, device == m_virtioNetDevices.end());
57
+ return m_deviceHostSupport->GetVirtioNetDevice(device->second);
58
+}
59
+
60
void GuestDeviceManager::AddRemoteFileSystem(_In_ REFCLSID clsid, _In_ PCWSTR tag, _In_ const wil::com_ptr<IPlan9FileSystem>& server)
61
{
62
m_deviceHostSupport->AddRemoteFileSystem(clsid, tag, server);
63
}
64
77
-void GuestDeviceManager::AddSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken)
65
+void GuestDeviceManager::AddSharedMemoryDevice(_In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken)
66
{
67
auto guestDeviceLock = m_lock.lock_exclusive();
68
auto objectLifetime = CreateSectionObjectRoot(Path, UserToken);
69
82
- // For virtiofs hdv, the flags parameter has been overloaded. Flags are placed in the lower
83
- // 16 bits, while the shared memory size in megabytes are placed in the upper 16 bits.
84
- static constexpr auto VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT = 16;
85
- UINT32 flags = (SizeMb << VIRTIO_FS_FLAGS_SHMEM_SIZE_SHIFT);
86
- WI_SetFlag(flags, VIRTIO_FS_FLAGS_TYPE_SECTIONS);
87
- (void)AddHdvShareWithOptions(VIRTIO_FS_DEVICE_ID, ImplementationClsid, Tag, {}, objectLifetime.Path.c_str(), flags, UserToken);
70
+ (void)m_deviceHostSupport->AddVirtiofsDevice(
71
+ UserToken, Tag, objectLifetime.Path, VirtiofsShareKind_SectionBacked, SizeMb, L"");
72
m_objectDirectories.emplace_back(std::move(objectLifetime));
73
}
74
@@ -149,9 +133,23 @@ wil::com_ptr<IPlan9FileSystem> GuestDeviceManager::GetRemoteFileSystem(_In_ REFC
133
return m_deviceHostSupport->GetRemoteFileSystem(clsid, tag);
134
}
135
136
+void GuestDeviceManager::SetSwiotlb(UINT64 GpaBase, UINT64 SizeBytes)
137
+{
138
+ m_deviceHostSupport->SetSwiotlb(GpaBase, SizeBytes);
139
+}
140
+
141
_Requires_lock_not_held_(m_lock)
153
-void GuestDeviceManager::RemoveGuestDevice(_In_ const GUID& DeviceId, _In_ const GUID& InstanceId)
142
+void GuestDeviceManager::RemoveGuestDevice(_In_ const GUID& InstanceId)
143
{
144
auto guestDeviceLock = m_lock.lock_exclusive();
156
- m_deviceHostSupport->RemoveDevice(DeviceId, InstanceId);
145
+ for (auto it = m_virtioNetDevices.begin(); it != m_virtioNetDevices.end(); ++it)
146
+ {
147
+ if (IsEqualGUID(it->second, InstanceId))
148
+ {
149
+ m_virtioNetDevices.erase(it);
150
+ break;
151
+ }
152
+ }
153
+
154
+ m_deviceHostSupport->RemoveDevice(InstanceId);
155
}
src/windows/common/GuestDeviceManager.h
+20
-40
@@ -4,27 +4,13 @@
4
5
#include "DeviceHostProxy.h"
6
7
-// Flags for virtiofs vdev device creation.
8
-#define VIRTIO_FS_FLAGS_TYPE_FILES 0x8000
9
-#define VIRTIO_FS_FLAGS_TYPE_SECTIONS 0x4000
10
-
7
inline const std::wstring c_defaultDeviceTag = L"default";
8
13
-// Use vcpus=1 so the device exposes a single virtio queue, bounding concurrent
14
-// guest-memory apertures to avoid hitting the host VID's 512-aperture quota.
15
-// TODO: revisit when the devicehost supports multiple shares per device.
16
-inline const std::wstring c_vcpusOption = L"vcpus=1";
17
-
18
-// These device types and class IDs are implemented by the external wsldevicehost vdev.
19
-DEFINE_GUID(VIRTIO_FS_DEVICE_ID, 0x872270E1, 0xA899, 0x4AF6, 0xB4, 0x54, 0x71, 0x93, 0x63, 0x44, 0x35, 0xAD); // {872270E1-A899-4AF6-B454-7193634435AD}
20
-DEFINE_GUID(VIRTIO_FS_ADMIN_CLASS_ID, 0x7E6AD219, 0xD1B3, 0x42D5, 0xB8, 0xEE, 0xD9, 0x63, 0x24, 0xE6, 0x4F, 0xF6); // {7E6AD219-D1B3-42D5-B8EE-D96324E64FF6}
21
-DEFINE_GUID(VIRTIO_FS_CLASS_ID, 0x60285AE6, 0xAAF3, 0x4456, 0xB4, 0x44, 0xA6, 0xC2, 0xD0, 0xDE, 0xDA, 0x38); // {60285AE6-AAF3-4456-B444-A6C2D0DEDA38}
22
-
23
-DEFINE_GUID(VIRTIO_NET_DEVICE_ID, 0xF07010D0, 0x0EA9, 0x447F, 0x88, 0xEF, 0xBD, 0x95, 0x2A, 0x4D, 0x2F, 0x14); // {F07010D0-0EA9-447F-88EF-BD952A4D2F14}
24
-DEFINE_GUID(VIRTIO_NET_CLASS_ID, 0x9E0D1898, 0xCA63, 0x424E, 0x8D, 0x49, 0x9D, 0x60, 0x67, 0xA3, 0x6B, 0xCE); // {9E0D1898-CA63-424E-8D49-9D6067A36BCE}
25
-
26
-DEFINE_GUID(VIRTIO_PMEM_DEVICE_ID, 0xEDBB24BB, 0x5E19, 0x40F4, 0x8A, 0x0F, 0x82, 0x24, 0x31, 0x30, 0x64, 0xFD); // {EDBB24BB-5E19-40F4-8A0F-8224313064FD}
27
-DEFINE_GUID(VIRTIO_PMEM_CLASS_ID, 0xABB755FC, 0x1B86, 0x4255, 0x83, 0xE2, 0xE5, 0x78, 0x7A, 0xBC, 0xF6, 0xC2); // {ABB755FC-1B86-4255-83E2-E5787ABCF6C2}
9
+struct VirtioFsShareOptions
10
+{
11
+ VirtiofsShareKind Kind = VirtiofsShareKind_FileBacked;
12
+ UINT32 SharedMemorySizeMb = 0;
13
+};
14
15
//
16
// Provides synchronized access to guest device operations.
@@ -32,42 +18,35 @@ DEFINE_GUID(VIRTIO_PMEM_CLASS_ID, 0xABB755FC, 0x1B86, 0x4255, 0x83, 0xE2, 0xE5,
18
class GuestDeviceManager
19
{
20
public:
35
- GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId);
21
+ GuestDeviceManager(_In_ const std::wstring& machineId, _In_ const GUID& runtimeId, bool EnableTelemetry = true);
22
~GuestDeviceManager();
23
24
_Requires_lock_not_held_(m_lock)
39
- GUID AddGuestDevice(
40
- _In_ const GUID& DeviceId,
41
- _In_ const GUID& ImplementationClsid,
42
- _In_ PCWSTR AccessName,
43
- _In_opt_ PCWSTR Options,
44
- _In_ PCWSTR Path,
45
- _In_ UINT32 Flags,
46
- _In_ HANDLE UserToken);
25
+ GUID AddVirtiofsDevice(_In_ PCWSTR Label, _In_opt_ PCWSTR MountOptions, _In_ PCWSTR RootPath, _In_ HANDLE UserToken, VirtioFsShareOptions Options = {});
26
+
27
+ _Requires_lock_not_held_(m_lock)
28
+ GUID AddVirtioPmemDevice(_In_ PCWSTR Path, bool ReadOnly, _In_ HANDLE UserToken);
29
30
_Requires_lock_not_held_(m_lock)
31
GUID AddNewDevice(_In_ const GUID& deviceId, _In_ const wil::com_ptr<IPlan9FileSystem>& server, _In_ PCWSTR tag);
32
33
+ _Requires_lock_not_held_(m_lock)
34
+ GUID AddVirtioNetDevice(_In_ PCWSTR Tag, const WslVirtioNetConfig& Config, const std::vector<IpAddress>& Nameservers, _In_ HANDLE UserToken);
35
+
36
+ wil::com_ptr<IWslVirtioNetDevice> GetVirtioNetDevice(_In_ PCWSTR Tag);
37
+
38
void AddRemoteFileSystem(_In_ REFCLSID clsid, _In_ PCWSTR tag, _In_ const wil::com_ptr<IPlan9FileSystem>& server);
39
53
- void AddSharedMemoryDevice(_In_ const GUID& ImplementationClsid, _In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken);
40
+ void AddSharedMemoryDevice(_In_ PCWSTR Tag, _In_ PCWSTR Path, _In_ UINT32 SizeMb, _In_ HANDLE UserToken);
41
42
wil::com_ptr<IPlan9FileSystem> GetRemoteFileSystem(_In_ REFCLSID clsid, _In_ std::wstring_view tag);
43
44
+ void SetSwiotlb(UINT64 GpaBase, UINT64 SizeBytes);
45
+
46
_Requires_lock_not_held_(m_lock)
58
- void RemoveGuestDevice(_In_ const GUID& DeviceId, _In_ const GUID& InstanceId);
47
+ void RemoveGuestDevice(_In_ const GUID& InstanceId);
48
49
private:
61
- _Requires_lock_held_(m_lock)
62
- GUID AddHdvShareWithOptions(
63
- _In_ const GUID& DeviceId,
64
- _In_ const GUID& ImplementationClsid,
65
- _In_ PCWSTR AccessName,
66
- _In_opt_ PCWSTR Options,
67
- _In_ PCWSTR Path,
68
- _In_ UINT32 Flags,
69
- _In_ HANDLE UserToken);
70
-
50
struct DirectoryObjectLifetime
51
{
52
std::wstring Path;
@@ -82,4 +61,5 @@ private:
61
std::wstring m_machineId;
62
wil::com_ptr<DeviceHostProxy> m_deviceHostSupport;
63
_Guarded_by_(m_lock) std::vector<DirectoryObjectLifetime> m_objectDirectories;
64
+ _Guarded_by_(m_lock) std::map<std::wstring, GUID> m_virtioNetDevices;
65
};
src/windows/service/exe/HcsVirtualMachine.cpp
+11
-31
@@ -81,7 +81,6 @@ HcsVirtualMachine::HcsVirtualMachine(_In_ const WSLCSessionSettings* Settings)
81
82
// Store the user token.
83
m_userToken = wil::shared_handle{wsl::windows::common::security::GetUserToken(TokenImpersonation).release()};
84
- m_virtioFsClassId = wsl::windows::common::security::IsTokenElevated(m_userToken.get()) ? VIRTIO_FS_ADMIN_CLASS_ID : VIRTIO_FS_CLASS_ID;
84
m_crashDumpFolder = GetCrashDumpFolder();
85
86
std::lock_guard lock(m_lock);
@@ -155,8 +154,7 @@ HcsVirtualMachine::HcsVirtualMachine(_In_ const WSLCSessionSettings* Settings)
154
155
#endif
156
158
- // Compute a swiotlb device-options token sized to fit this VM's RAM, used by the kernel
159
- // command line, virtiofs shares, and the Consomme virtio-net adapter.
157
+ // Compute a swiotlb size that fits this VM's RAM for the kernel command line.
158
// Only needed when a virtio device that requires bounce buffers will be attached.
159
ULONG64 swiotlbSizeBytes = 0;
160
if (FeatureEnabled(WslcFeatureFlagsVirtioFs) || m_networkingMode == WSLCNetworkingModeConsomme)
@@ -503,7 +501,7 @@ try
501
}
502
503
m_networkEngine = std::make_unique<wsl::core::ConsommeNetworking>(
506
- wsl::core::GnsChannel(std::move(gnsSocketHandle)), flags, nullptr, m_guestDeviceManager, m_userToken, m_swiotlbOption);
504
+ wsl::core::GnsChannel(std::move(gnsSocketHandle)), flags, nullptr, m_guestDeviceManager, m_userToken);
505
}
506
else
507
{
@@ -621,31 +619,8 @@ try
619
else
620
{
621
std::wstring options = ReadOnly ? L"ro" : L"";
624
- auto appendOption = [&options](const std::wstring& option) {
625
- if (option.empty())
626
- {
627
- return;
628
- }
629
-
630
- if (!options.empty())
631
- {
632
- options += L";";
633
- }
634
-
635
- options += option;
636
- };
637
-
638
- appendOption(m_swiotlbOption);
639
- appendOption(c_vcpusOption);
622
641
- it->second = m_guestDeviceManager->AddGuestDevice(
642
- VIRTIO_FS_DEVICE_ID,
643
- m_virtioFsClassId,
644
- shareName.c_str(),
645
- options.c_str(),
646
- WindowsPath,
647
- VIRTIO_FS_FLAGS_TYPE_FILES,
648
- m_userToken.get());
623
+ it->second = m_guestDeviceManager->AddVirtiofsDevice(shareName.c_str(), options.c_str(), WindowsPath, m_userToken.get());
624
}
625
626
cleanup.release();
@@ -670,7 +645,7 @@ try
645
}
646
else
647
{
673
- m_guestDeviceManager->RemoveGuestDevice(VIRTIO_FS_DEVICE_ID, it->second.value());
648
+ m_guestDeviceManager->RemoveGuestDevice(it->second.value());
649
}
650
651
m_shares.erase(it);
@@ -686,11 +661,16 @@ try
661
662
std::lock_guard lock(m_lock);
663
689
- THROW_HR_IF(E_INVALIDARG, !m_swiotlbOption.empty());
664
+ THROW_HR_IF(E_INVALIDARG, m_swiotlbConfigured);
665
666
if (Capabilities->HvPciSwiotlbBase != 0 && Capabilities->HvPciSwiotlbSize != 0)
667
{
693
- m_swiotlbOption = std::format(L"swiotlb=0x{:x},{}", Capabilities->HvPciSwiotlbBase, Capabilities->HvPciSwiotlbSize);
668
+ if (m_guestDeviceManager)
669
+ {
670
+ m_guestDeviceManager->SetSwiotlb(Capabilities->HvPciSwiotlbBase, Capabilities->HvPciSwiotlbSize);
671
+ }
672
+
673
+ m_swiotlbConfigured = true;
674
}
675
676
WSL_LOG(
src/windows/service/exe/HcsVirtualMachine.h
+1
-4
@@ -82,13 +82,10 @@ private:
82
ULONG m_bootTimeoutMs{};
83
84
wil::shared_handle m_userToken;
85
- GUID m_virtioFsClassId{};
86
-
85
WSLCFeatureFlags m_featureFlags{};
86
WSLCNetworkingMode m_networkingMode{};
87
90
- // Swiotlb device-options token sized to fit inside the VM's RAM (empty when too small).
91
- std::wstring m_swiotlbOption;
88
+ bool m_swiotlbConfigured = false;
89
90
wil::unique_socket m_listenSocket;
91
wil::unique_event m_vmExitEvent{wil::EventOptions::ManualReset};
src/windows/service/exe/WslCoreVm.cpp
+7
-42
@@ -332,7 +332,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
332
WI_ASSERT(IsEqualGUID(VmId, m_runtimeId));
333
334
// Initialize the guest device manager.
335
- m_guestDeviceManager = std::make_shared<GuestDeviceManager>(m_machineId, m_runtimeId);
335
+ m_guestDeviceManager = std::make_shared<GuestDeviceManager>(m_machineId, m_runtimeId, m_vmConfig.EnableTelemetry);
336
337
// Create a socket listening for connections from mini_init.
338
m_listenSocket = wsl::windows::common::hvsocket::Listen(m_runtimeId, LX_INIT_UTILITY_VM_INIT_PORT);
@@ -440,7 +440,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
440
// requested via the kernel command line; otherwise the kernel correctly doesn't allocate.
441
if (m_hvPciSwiotlbBase != 0 && m_hvPciSwiotlbSize != 0)
442
{
443
- m_swiotlbOption = std::format(L"swiotlb=0x{:x},{}", m_hvPciSwiotlbBase, m_hvPciSwiotlbSize);
443
+ m_guestDeviceManager->SetSwiotlb(m_hvPciSwiotlbBase, m_hvPciSwiotlbSize);
444
}
445
else if (m_vmConfig.SwiotlbSizeBytes != 0)
446
{
@@ -615,7 +615,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
615
dnsTunnelingSocket.reset();
616
617
m_networkingEngine = std::make_unique<wsl::core::ConsommeNetworking>(
618
- std::move(gnsChannel), flags, LX_INIT_RESOLVCONF_FULL_HEADER, m_guestDeviceManager, m_userToken, m_swiotlbOption);
618
+ std::move(gnsChannel), flags, LX_INIT_RESOLVCONF_FULL_HEADER, m_guestDeviceManager, m_userToken);
619
}
620
else if (m_vmConfig.NetworkingMode == NetworkingMode::Bridged)
621
{
@@ -1842,10 +1842,7 @@ void WslCoreVm::InitializeGuest()
1842
{
1843
try
1844
{
1845
- // Use the appropriate virtiofs class ID based on m_userToken elevation.
1846
- const bool admin = wsl::windows::common::security::IsTokenElevated(m_userToken.get());
1847
- const GUID classId = admin ? VIRTIO_FS_ADMIN_CLASS_ID : VIRTIO_FS_CLASS_ID;
1848
- m_guestDeviceManager->AddSharedMemoryDevice(classId, L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB, m_userToken.get());
1845
+ m_guestDeviceManager->AddSharedMemoryDevice(L"wslg", L"wslg", WSLG_SHARED_MEMORY_SIZE_MB, m_userToken.get());
1846
m_sharedMemoryRoot = std::format(L"WSL\\{}\\wslg", m_machineId);
1847
}
1848
CATCH_LOG()
@@ -2090,10 +2087,6 @@ void WslCoreVm::MountRootNamespaceFolder(_In_ LPCWSTR HostPath, _In_ LPCWSTR Gue
2087
ULONG
2088
WslCoreVm::MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly)
2089
{
2093
- hcs::Plan9ShareFlags flags{};
2094
-
2095
- WI_SetFlagIf(flags, hcs::Plan9ShareFlags::ReadOnly, ReadOnly);
2096
-
2090
// Serialize calls to mount pmem devices to the VM. Some quick background on why we do this.
2091
// The problem stems from the fact that our caller needs to know the dev path where the pmem
2092
// device will be mounted (i.e. /dev/pmem0). We could dynamically discover the device path and
@@ -2110,7 +2103,7 @@ WslCoreVm::MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly)
2103
// a symlink that points to a path like:
2104
// /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0004:00/VMBUS:00/<GUID>/pcicceb:00//cceb:00:00.0/virtio1/ndbus0/region0/namespace0.0/block/pmem0
2105
// Notice the GUID in the middle of that path. That GUID is the instance ID, which is randomly
2113
- // generated by AddGuestDevice. So once we find a path with the instance ID, we know that
2106
+ // generated by AddVirtioPmemDevice. So once we find a path with the instance ID, we know that
2107
// eventually /dev/pmemX will appear in the guest.
2108
auto persistentMemoryLock = m_persistentMemoryLock.lock_exclusive();
2109
@@ -2120,10 +2113,7 @@ WslCoreVm::MountFileAsPersistentMemory(_In_ PCWSTR FilePath, _In_ bool ReadOnly)
2113
// doesn't currently support this. For now, we rely on the fact that all pmem devices are
2114
// added as part of VM creation and therefore any failure will result in VM termination
2115
// (in which case there's no need to remove the device).
2123
- {
2124
- (void)m_guestDeviceManager->AddGuestDevice(
2125
- VIRTIO_PMEM_DEVICE_ID, VIRTIO_PMEM_CLASS_ID, L"", nullptr, FilePath, static_cast<UINT32>(flags), m_userToken.get());
2126
- }
2116
+ (void)m_guestDeviceManager->AddVirtioPmemDevice(FilePath, ReadOnly, m_userToken.get());
2117
2118
// Wait for the pmem device to appear in the VM at /dev/pmemX. Guess the value of X given the
2119
// number of pmem devices that have been exposed to the VM. See above for more details why.
@@ -2194,25 +2184,7 @@ std::pair<std::wstring, std::wstring> WslCoreVm::AddVirtioFsShare(_In_ bool Admi
2184
2185
sharePath = std::filesystem::weakly_canonical(sharePath).wstring();
2186
2197
- // Append swiotlb and vcpus here to cover the fixed-drive, dynamic add, and remount paths.
2198
- // Safe to duplicate: both tokens are constant per VM, and VirtioFsShare collapses repeats into one map entry.
2187
std::wstring effectiveOptions(Options);
2200
- auto appendOption = [&effectiveOptions](const std::wstring& option) {
2201
- if (option.empty())
2202
- {
2203
- return;
2204
- }
2205
-
2206
- if (!effectiveOptions.empty())
2207
- {
2208
- effectiveOptions += L';';
2209
- }
2210
-
2211
- effectiveOptions += option;
2212
- };
2213
-
2214
- appendOption(m_swiotlbOption);
2215
- appendOption(c_vcpusOption);
2188
2189
// Check if a matching share already exists.
2190
bool created = false;
@@ -2229,14 +2201,7 @@ std::pair<std::wstring, std::wstring> WslCoreVm::AddVirtioFsShare(_In_ bool Admi
2201
tag = wsl::shared::string::GuidToString<wchar_t>(tagGuid, wsl::shared::string::None);
2202
WI_ASSERT(!FindVirtioFsShare(tag.c_str(), Admin));
2203
2232
- (void)m_guestDeviceManager->AddGuestDevice(
2233
- VIRTIO_FS_DEVICE_ID,
2234
- Admin ? VIRTIO_FS_ADMIN_CLASS_ID : VIRTIO_FS_CLASS_ID,
2235
- tag.c_str(),
2236
- key.OptionsString().c_str(),
2237
- sharePath.c_str(),
2238
- VIRTIO_FS_FLAGS_TYPE_FILES,
2239
- UserToken);
2204
+ (void)m_guestDeviceManager->AddVirtiofsDevice(tag.c_str(), key.OptionsString().c_str(), sharePath.c_str(), UserToken);
2205
2206
m_virtioFsShares.emplace(std::move(key), tag);
2207
created = true;
src/windows/service/exe/WslCoreVm.h
-1
@@ -308,7 +308,6 @@ private:
308
bool m_seccompAvailable;
309
uint64_t m_hvPciSwiotlbBase = 0;
310
uint64_t m_hvPciSwiotlbSize = 0;
311
- std::wstring m_swiotlbOption;
311
std::wstring m_sharedMemoryRoot;
312
std::filesystem::path m_installPath;
313
std::wstring m_userProfile;
src/windows/service/inc/wslc.idl
+4
-5
@@ -406,11 +406,10 @@ interface IWSLCVirtualMachine : IUnknown
406
HRESULT RemoveShare([in] REFGUID ShareId);
407
408
// Configures the per-VM state discovered from the guest kernel after boot
409
- // (currently the hv_pci swiotlb pool). Subsequent calls to AddShare and
410
- // ConfigureNetworking forward these values to wsldevicehost via the
411
- // swiotlb device-options token. A capabilities struct whose fields are
412
- // all zero means the guest kernel does not support the feature; the
413
- // token is then omitted.
409
+ // (currently the hv_pci swiotlb pool). Non-zero values are forwarded to
410
+ // wsldevicehost before virtiofs shares or Consomme networking devices are
411
+ // created. A capabilities struct whose fields are all zero means the guest
412
+ // kernel does not support the feature.
413
HRESULT ApplyGuestCapabilities([in] const WSLCGuestCapabilities* Capabilities);
414
415
// Returns an event that is signaled when the VM exits (graceful or forced).
src/windows/wslcsession/WSLCVirtualMachine.cpp
+3
-5
@@ -314,8 +314,7 @@ void WSLCVirtualMachine::Initialize()
314
Mount(m_initChannel, modulesDevice.c_str(), "", "ext4", "ro", WSLC_MOUNT::KernelModules);
315
316
// Discover the per-VM guest capabilities (currently the hv_pci swiotlb pool) and forward them
317
- // to the service so virtio device-options (virtiofs shares, Consomme networking) can include
318
- // the swiotlb token.
317
+ // to the service before virtiofs shares or Consomme networking devices are created.
318
ReadGuestCapabilities();
319
320
// Configure GPU mounts if enabled
@@ -433,9 +432,8 @@ void WSLCVirtualMachine::ReadGuestCapabilities()
432
TraceLoggingValue(m_hvPciSwiotlbBase, "HvPciSwiotlbBase"),
433
TraceLoggingValue(m_hvPciSwiotlbSize, "HvPciSwiotlbSize"));
434
436
- // Forward the values to the service so AddShare and ConfigureNetworking can include the
437
- // swiotlb device-options token. Passing zero for both means the guest kernel does not
438
- // support hv_pci swiotlb; the service then omits the token.
435
+ // Forward the values to the service so AddShare and ConfigureNetworking can configure
436
+ // wsldevicehost. Passing zero for both means the guest kernel does not support hv_pci swiotlb.
437
WSLCGuestCapabilities capabilities{};
438
capabilities.HvPciSwiotlbBase = m_hvPciSwiotlbBase;
439
capabilities.HvPciSwiotlbSize = m_hvPciSwiotlbSize;
src/windows/wslcsession/WSLCVirtualMachine.h
+2
-2
@@ -197,8 +197,8 @@ private:
197
void ConfigureNetworking();
198
199
// Queries the guest kernel for per-VM capabilities (currently the hv_pci swiotlb pool
200
- // reserved at boot) and forwards them to the service so that subsequent virtio device-options
201
- // can include the swiotlb token. Called after the root filesystem is mounted.
200
+ // reserved at boot) and forwards them to the service before virtio devices are created.
201
+ // Called after the root filesystem is mounted.
202
void ReadGuestCapabilities();
203
204
static void Mount(wsl::shared::SocketChannel& Channel, LPCSTR Source, _In_ LPCSTR Target, _In_ LPCSTR Type, _In_ LPCSTR Options, _In_ ULONG Flags);
src/windows/wsldevicehoststub/CMakeLists.txt
new
+25
@@ -0,0 +1,25 @@
1
+set(SOURCES
2
+ ${CMAKE_CURRENT_BINARY_DIR}/inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WslDeviceHost_i_${TARGET_PLATFORM}.c
3
+ ${CMAKE_CURRENT_BINARY_DIR}/inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WslDeviceHost_p_${TARGET_PLATFORM}.c
4
+ ${CMAKE_CURRENT_BINARY_DIR}/inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/dlldata_${TARGET_PLATFORM}.c
5
+ ${CMAKE_CURRENT_LIST_DIR}/WslDeviceHostProxyStub.def
6
+ ${CMAKE_CURRENT_LIST_DIR}/WslDeviceHostProxyStub.rc)
7
+
8
+set_source_files_properties(${SOURCES} PROPERTIES GENERATED TRUE)
9
+
10
+add_library(wsldevicehostproxystub SHARED ${SOURCES})
11
+add_dependencies(wsldevicehostproxystub wsldevicehostidl)
12
+
13
+# The generated dlldata.c uses ENTRY_PREFIX/REGISTER_PROXY_DLL only when those
14
+# macros are pre-defined. midl-generated proxy code resolves IIDs via the _i.c
15
+# definitions and links against rpcrt4/ole32 like classic-COM proxies.
16
+target_link_libraries(wsldevicehostproxystub ${COMMON_LINK_LIBRARIES})
17
+
18
+# The proxy/stub file uses `#define REGISTER_PROXY_DLL` so DllRegisterServer is
19
+# emitted. This lets `regsvr32` work for developer/ad-hoc registration; the
20
+# production install drives registration via MSI tables (see msipackage/package.wix.in).
21
+target_compile_definitions(wsldevicehostproxystub PRIVATE
22
+ REGISTER_PROXY_DLL
23
+ PROXY_CLSID_IS={0x6D32A4B7,0x9E1F,0x4C82,{0xA5,0x73,0xF8,0xB1,0xC4,0xD2,0x9E,0x60}})
24
+
25
+set_target_properties(wsldevicehostproxystub PROPERTIES FOLDER windows)
src/windows/wsldevicehoststub/WslDeviceHostProxyStub.def
new
+7
@@ -0,0 +1,7 @@
1
+LIBRARY WslDeviceHostProxyStub.dll
2
+
3
+EXPORTS
4
+ DllGetClassObject PRIVATE
5
+ DllCanUnloadNow PRIVATE
6
+ DllRegisterServer PRIVATE
7
+ DllUnregisterServer PRIVATE
src/windows/wsldevicehoststub/WslDeviceHostProxyStub.rc
new
+16
@@ -0,0 +1,16 @@
1
+// Copyright (C) Microsoft Corporation. All rights reserved.
2
+//
3
+// Resource file for wsldevicehostproxystub.dll, the COM proxy/stub for the
4
+// WslDeviceHost interfaces (IWslDeviceHost, IWslVm, IWslVirtio*Device,
5
+// IWslDeviceHostCallback). Built from the proxy/stub C source generated by
6
+// midl from WslDeviceHost.idl shipped in the Microsoft.WSL.DeviceHost nuget.
7
+
8
+#include <windows.h>
9
+#include "wslversioninfo.h"
10
+
11
+#define VER_INTERNALNAME_STR "wsldevicehostproxystub.dll"
12
+#define VER_ORIGINALFILENAME_STR "wsldevicehostproxystub.dll"
13
+
14
+#define VER_FILEDESCRIPTION_STR "WSL Device Host ProxyStub DLL"
15
+
16
+#include <common.ver>
src/windows/wsldevicehoststub/inc/CMakeLists.txt
new
+3
@@ -0,0 +1,3 @@
1
+add_idl(wsldevicehostidl "${WSL_DEVICE_HOST_SOURCE_DIR}/idl/WslDeviceHost.idl" "")
2
+
3
+set_target_properties(wsldevicehostidl PROPERTIES FOLDER windows)
test/windows/UnitTests.cpp
+12
-2
@@ -2526,8 +2526,18 @@ Error code: Wsl/InstallDistro/WSL_E_DISTRO_NOT_FOUND
2526
// Keys that are only created by the MSI.
2527
const std::vector<LPCWSTR> serviceKeys{
2528
L"SOFTWARE\\Microsoft\\Terminal Server Client\\Default\\OptionalAddIns\\WSLDVC_PACKAGE",
2529
- L"SOFTWARE\\Classes\\CLSID\\{7e6ad219-d1b3-42d5-b8ee-d96324e64ff6}",
2530
- L"SOFTWARE\\Classes\\AppID\\{17696EAC-9568-4CF5-BB8C-82515AAD6C09}"};
2529
+ L"SOFTWARE\\Classes\\AppID\\{17696EAC-9568-4CF5-BB8C-82515AAD6C09}",
2530
+ L"SOFTWARE\\Classes\\CLSID\\{2C3E9A41-7B5D-4F18-93D6-A8C2E4F7B1D9}\\InProcServer32",
2531
+ L"SOFTWARE\\Classes\\CLSID\\{E3146082-A0DA-43A7-813B-A89EEE8C7628}\\InProcServer32",
2532
+ L"SOFTWARE\\Classes\\CLSID\\{4F9C8B23-D6E1-4A85-BF2A-E7C5D8F931A6}\\InProcServer32",
2533
+ L"SOFTWARE\\Classes\\CLSID\\{9C9C7131-D756-48FA-BD49-734E75AF37C0}\\InProcServer32",
2534
+ L"SOFTWARE\\Classes\\CLSID\\{6D32A4B7-9E1F-4C82-A573-F8B1C4D29E60}\\InProcServer32",
2535
+ L"SOFTWARE\\Classes\\Interface\\{27394DCF-6383-4E4E-BB0A-C13D4E5F6071}\\ProxyStubClsid32",
2536
+ L"SOFTWARE\\Classes\\Interface\\{D2F47B8A-1E3C-4D9F-A6B5-7C8E9F0A1B2C}\\ProxyStubClsid32",
2537
+ L"SOFTWARE\\Classes\\Interface\\{E3F58C9B-2F4D-4E0A-B7C6-8D9F0A1B2C3D}\\ProxyStubClsid32",
2538
+ L"SOFTWARE\\Classes\\Interface\\{F406DACB-3050-4F1B-A8D7-9E0A1B2C3D4E}\\ProxyStubClsid32",
2539
+ L"SOFTWARE\\Classes\\Interface\\{05172EBD-4161-4C2C-99E8-AF1B2C3D4E5F}\\ProxyStubClsid32",
2540
+ L"SOFTWARE\\Classes\\Interface\\{16283FCE-5272-4D3D-AAF9-B02C3D4E5F60}\\ProxyStubClsid32"};
2541
2542
for (const auto* keyName : serviceKeys)
2543
{