@samitouri / QOSAMI-WSL / commits / a5b93397

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 {