• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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