1 /* 2 * Copyright (c) 2021-2022 The Khronos Group Inc. 3 * Copyright (c) 2021-2022 Valve Corporation 4 * Copyright (c) 2021-2022 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and/or associated documentation files (the "Materials"), to 8 * deal in the Materials without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Materials, and to permit persons to whom the Materials are 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice(s) and this permission notice shall be included in 14 * all copies or substantial portions of the Materials. 15 * 16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 * 20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 23 * USE OR OTHER DEALINGS IN THE MATERIALS. 24 * 25 * Author: Charles Giessen <charles@lunarg.com> 26 */ 27 28 #pragma once 29 30 #include "test_util.h" 31 32 #include <unordered_set> 33 #include <stdlib.h> 34 35 #if defined(WIN32) 36 #include <strsafe.h> 37 #include <cfgmgr32.h> 38 #include <initguid.h> 39 #include <devpkey.h> 40 #include <winternl.h> 41 #include <appmodel.h> 42 43 #define CINTERFACE 44 #include <dxgi1_6.h> 45 #include <adapters.h> 46 #endif 47 48 enum class ManifestCategory { implicit_layer, explicit_layer, icd, settings }; 49 enum class GpuType { unspecified, integrated, discrete, external }; 50 51 #if defined(WIN32) 52 #define VK_VARIANT_REG_STR "" 53 #define VK_VARIANT_REG_STR_W L"" 54 55 #define VK_DRIVERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\Drivers" 56 #define VK_ELAYERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\ExplicitLayers" 57 #define VK_ILAYERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\ImplicitLayers" 58 #define VK_SETTINGS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\LoaderSettings" 59 60 struct RegistryEntry { 61 RegistryEntry() = default; RegistryEntryRegistryEntry62 RegistryEntry(std::filesystem::path const& name) noexcept : name(name) {} RegistryEntryRegistryEntry63 RegistryEntry(std::filesystem::path const& name, DWORD value) noexcept : name(name), value(value) {} 64 std::filesystem::path name; 65 DWORD value{}; 66 }; 67 68 struct HKeyHandle { HKeyHandleHKeyHandle69 explicit HKeyHandle(const size_t value, const std::string& key_path) noexcept : key(HKEY{}), path(key_path) { 70 key = reinterpret_cast<HKEY>(value); 71 } 72 getHKeyHandle73 HKEY get() const noexcept { return key; } 74 75 HKEY key{}; 76 std::string path; 77 }; 78 79 static const char* pnp_registry_path = "SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}"; 80 81 // Needed for DXGI mocking 82 struct KnownDriverData { 83 const char* filename = nullptr; 84 int vendor_id = 0; 85 }; 86 static std::array<KnownDriverData, 4> known_driver_list = { 87 #if defined(_WIN64) 88 KnownDriverData{"igvk64.json", 0x8086}, KnownDriverData{"nv-vk64.json", 0x10de}, KnownDriverData{"amd-vulkan64.json", 0x1002}, 89 KnownDriverData{"amdvlk64.json", 0x1002} 90 #else 91 KnownDriverData{"igvk32.json", 0x8086}, KnownDriverData{"nv-vk32.json", 0x10de}, KnownDriverData{"amd-vulkan32.json", 0x1002}, 92 KnownDriverData{"amdvlk32.json", 0x1002} 93 #endif 94 }; 95 96 struct DXGIAdapter { 97 GpuType gpu_preference = GpuType::unspecified; 98 DXGI_ADAPTER_DESC1 desc1{}; 99 uint32_t adapter_index = 0; 100 IDXGIAdapter1 adapter_instance{}; 101 IDXGIAdapter1Vtbl adapter_vtbl_instance{}; 102 }; 103 104 struct D3DKMT_Adapter { 105 D3DKMT_Adapter& add_driver_manifest_path(std::filesystem::path const& src); 106 D3DKMT_Adapter& add_implicit_layer_manifest_path(std::filesystem::path const& src); 107 D3DKMT_Adapter& add_explicit_layer_manifest_path(std::filesystem::path const& src); 108 109 UINT hAdapter; 110 LUID adapter_luid; 111 std::vector<std::wstring> driver_paths; 112 std::vector<std::wstring> implicit_layer_paths; 113 std::vector<std::wstring> explicit_layer_paths; 114 115 private: 116 D3DKMT_Adapter& add_path(std::filesystem::path src, std::vector<std::wstring>& dest); 117 }; 118 119 #elif COMMON_UNIX_PLATFORMS 120 121 struct DirEntry { 122 DIR* directory = nullptr; 123 std::string folder_path; 124 std::vector<struct dirent*> contents; 125 // the current item being read by an app (incremented by readdir, reset to zero by opendir & closedir) 126 size_t current_index = 0; 127 bool is_fake_path = false; // true when this entry is for folder redirection 128 }; 129 130 #endif 131 132 struct FrameworkEnvironment; // forward declaration 133 134 // Necessary to have inline definitions as shim is a dll and thus functions 135 // defined in the .cpp wont be found by the rest of the application 136 struct PlatformShim { PlatformShimPlatformShim137 PlatformShim() { fputs_stderr_log.reserve(65536); } PlatformShimPlatformShim138 PlatformShim(std::vector<fs::FolderManager>* folders) : folders(folders) { fputs_stderr_log.reserve(65536); } 139 140 // Used to get info about which drivers & layers have been added to folders 141 std::vector<fs::FolderManager>* folders; 142 143 // Captures the output to stderr from fputs & fputc - aka the output of loader_log() 144 std::string fputs_stderr_log; 145 146 // Test Framework interface 147 void reset(); 148 149 void redirect_all_paths(std::filesystem::path const& path); 150 void redirect_category(std::filesystem::path const& new_path, ManifestCategory category); 151 152 // fake paths are paths that the loader normally looks in but actually point to locations inside the test framework 153 void set_fake_path(ManifestCategory category, std::filesystem::path const& path); 154 155 // known paths are real paths but since the test framework guarantee's the order files are found in, files in these paths 156 // need to be ordered correctly 157 void add_known_path(std::filesystem::path const& path); 158 159 void add_manifest(ManifestCategory category, std::filesystem::path const& path); 160 void add_unsecured_manifest(ManifestCategory category, std::filesystem::path const& path); 161 clear_logsPlatformShim162 void clear_logs() { fputs_stderr_log.clear(); } find_in_logPlatformShim163 bool find_in_log(std::string const& search_text) const { return fputs_stderr_log.find(search_text) != std::string::npos; } 164 165 // platform specific shim interface 166 #if defined(WIN32) 167 // Control Platform Elevation Level set_elevated_privilegePlatformShim168 void set_elevated_privilege(bool elev) { elevation_level = (elev) ? SECURITY_MANDATORY_HIGH_RID : SECURITY_MANDATORY_LOW_RID; } 169 unsigned long elevation_level = SECURITY_MANDATORY_LOW_RID; 170 171 void add_dxgi_adapter(GpuType gpu_preference, DXGI_ADAPTER_DESC1 desc1); 172 void add_d3dkmt_adapter(D3DKMT_Adapter const& adapter); 173 void set_app_package_path(std::filesystem::path const& path); 174 175 std::unordered_map<uint32_t, DXGIAdapter> dxgi_adapters; 176 177 std::vector<D3DKMT_Adapter> d3dkmt_adapters; 178 179 // TODO: 180 void add_CM_Device_ID(std::wstring const& id, std::filesystem::path const& icd_path, std::filesystem::path const& layer_path); 181 std::wstring CM_device_ID_list = {L'\0'}; 182 std::vector<RegistryEntry> CM_device_ID_registry_keys; 183 184 uint32_t random_base_path = 0; 185 186 std::vector<std::filesystem::path> icd_paths; 187 188 std::vector<RegistryEntry> hkey_current_user_explicit_layers; 189 std::vector<RegistryEntry> hkey_current_user_implicit_layers; 190 std::vector<RegistryEntry> hkey_local_machine_explicit_layers; 191 std::vector<RegistryEntry> hkey_local_machine_implicit_layers; 192 std::vector<RegistryEntry> hkey_local_machine_drivers; 193 std::vector<RegistryEntry> hkey_local_machine_settings; 194 std::vector<RegistryEntry> hkey_current_user_settings; 195 196 std::wstring app_package_path; 197 198 // When a key is created, return the index of the 199 size_t created_key_count = 0; 200 std::vector<HKeyHandle> created_keys; 201 202 #elif COMMON_UNIX_PLATFORMS 203 bool is_fake_path(std::filesystem::path const& path); 204 std::filesystem::path const& get_real_path_from_fake_path(std::filesystem::path const& path); 205 206 void redirect_path(std::filesystem::path const& path, std::filesystem::path const& new_path); 207 void remove_redirect(std::filesystem::path const& path); 208 209 bool is_known_path(std::filesystem::path const& path); 210 void remove_known_path(std::filesystem::path const& path); 211 212 void redirect_dlopen_name(std::filesystem::path const& filename, std::filesystem::path const& actual_path); 213 bool is_dlopen_redirect_name(std::filesystem::path const& filename); 214 215 std::filesystem::path query_default_redirect_path(ManifestCategory category); 216 217 std::unordered_map<std::string, std::filesystem::path> redirection_map; 218 std::unordered_map<std::string, std::filesystem::path> dlopen_redirection_map; 219 std::unordered_set<std::string> known_path_set; 220 set_elevated_privilegePlatformShim221 void set_elevated_privilege(bool elev) { use_fake_elevation = elev; } 222 bool use_fake_elevation = false; 223 224 std::vector<DirEntry> dir_entries; 225 226 #if defined(__APPLE__) 227 std::string bundle_contents; 228 #endif 229 #endif 230 bool is_during_destruction = false; 231 }; 232 233 std::vector<std::string> parse_env_var_list(std::string const& var); 234 std::string category_path_name(ManifestCategory category); 235 236 std::vector<std::filesystem::path> get_folder_contents(std::vector<fs::FolderManager>* folders, 237 std::filesystem::path folder_name) noexcept; 238 239 extern "C" { 240 // dynamically link on windows and macos 241 #if defined(WIN32) || defined(__APPLE__) 242 using PFN_get_platform_shim = PlatformShim* (*)(std::vector<fs::FolderManager>* folders); 243 #define GET_PLATFORM_SHIM_STR "get_platform_shim" 244 245 #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__GNU__) || defined(__QNX__) 246 // statically link on linux 247 PlatformShim* get_platform_shim(std::vector<fs::FolderManager>* folders); 248 #endif 249 } 250