1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief VK_EXT_device_fault extension tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktPostmortemDeviceFaultTests.hpp"
25 #include "vktCustomInstancesDevices.hpp"
26 
27 #include "deStringUtil.hpp"
28 #include "vkDefs.hpp"
29 #include "vktTestCase.hpp"
30 #include "vktTestGroupUtil.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuCommandLine.hpp"
33 
34 #include <functional>
35 #include <limits>
36 #include <sstream>
37 #include <utility>
38 #include <vector>
39 
40 #define ARRAY_LENGTH(a_) std::extent<decltype(a_)>::value
41 
42 #ifndef VK_EXT_DEVICE_FAULT_EXTENSION_NAME
43 #define VK_EXT_DEVICE_FAULT_EXTENSION_NAME "VK_EXT_device_fault"
44 #else
45 // This should never have happened
46 // static_assert(false, "Trying to redefine VK_EXT_DEVICE_FAULT_EXTENSION_NAME");
47 #endif
48 
49 namespace vkt
50 {
51 namespace postmortem
52 {
53 namespace
54 {
55 using namespace vk;
56 using namespace tcu;
57 
58 enum class TestType
59 {
60     Fake,
61     Real,
62     CustomDevice
63 };
64 
65 struct TestParams
66 {
67     TestType type;
68 };
69 
70 class DeviceFaultCase : public TestCase
71 {
72 public:
DeviceFaultCase(TestContext & testCtx,const std::string & name,const TestParams & params)73     DeviceFaultCase(TestContext &testCtx, const std::string &name, const TestParams &params)
74         : TestCase(testCtx, name)
75         , m_params(params)
76     {
77     }
78     virtual ~DeviceFaultCase() = default;
79     virtual TestInstance *createInstance(Context &context) const override;
80     virtual void checkSupport(Context &context) const override;
81 
82 private:
83     const TestParams m_params;
84 };
85 
86 class DeviceFaultInstance : public TestInstance
87 {
88 public:
DeviceFaultInstance(Context & context,const TestParams & params)89     DeviceFaultInstance(Context &context, const TestParams &params) : TestInstance(context), m_params(params)
90     {
91     }
92     virtual ~DeviceFaultInstance() = default;
93 
94     virtual TestStatus iterate(void) override;
95     void log(const std::vector<VkDeviceFaultAddressInfoEXT> &addressInfos,
96              const std::vector<VkDeviceFaultVendorInfoEXT> &vendorInfos,
97              const std::vector<uint8_t> &vendorBinaryData) const;
98 
99 private:
100     const TestParams m_params;
101 };
102 
103 class DeviceFaultCustomInstance : public TestInstance
104 {
105 public:
DeviceFaultCustomInstance(Context & context)106     DeviceFaultCustomInstance(Context &context) : TestInstance(context)
107     {
108     }
109     virtual ~DeviceFaultCustomInstance() = default;
110 
111     virtual TestStatus iterate(void) override;
112 };
113 
createInstance(Context & context) const114 TestInstance *DeviceFaultCase::createInstance(Context &context) const
115 {
116     TestInstance *instance = nullptr;
117     if (m_params.type == TestType::CustomDevice)
118         instance = new DeviceFaultCustomInstance(context);
119     else
120         instance = new DeviceFaultInstance(context, m_params);
121     return instance;
122 }
123 
124 class CustomDevice
125 {
126     Move<VkDevice> m_logicalDevice;
127 
128 public:
CustomDevice(Context & context)129     CustomDevice(Context &context)
130     {
131         const bool useValidation                   = context.getTestContext().getCommandLine().isValidationEnabled();
132         const PlatformInterface &platformInterface = context.getPlatformInterface();
133         const VkInstance instance                  = context.getInstance();
134         const InstanceInterface &instanceInterface = context.getInstanceInterface();
135         const VkPhysicalDevice physicalDevice      = context.getPhysicalDevice();
136         const uint32_t queueFamilyIndex            = context.getUniversalQueueFamilyIndex();
137         const float queuePriority                  = 1.0f;
138 
139         const VkDeviceQueueCreateInfo queueCreateInfo{
140             VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
141             nullptr,                                    // const void* pNext;
142             0,                                          // VkDeviceQueueCreateFlags flags;
143             queueFamilyIndex,                           // uint32_t queueFamilyIndex;
144             1u,                                         // uint32_t queueCount;
145             &queuePriority                              // const float* pQueuePriorities;
146         };
147 
148         VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures{
149             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT, // VkStructureType sType;
150             nullptr,                                              // void* pNext;
151             VK_TRUE,                                              // VkBool32 deviceFault;
152             VK_TRUE                                               // VkBool32 deviceFaultVendorBinary;
153         };
154 
155         VkPhysicalDeviceFeatures2 deviceFeatures2{
156             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, // VkStructureType sType;
157             &deviceFaultFeatures,                         // void* pNext;
158             {/* zeroed automatically since c++11 */}      // VkPhysicalDeviceFeatures features;
159         };
160         instanceInterface.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
161 
162         const VkDeviceCreateInfo deviceCreateInfo{
163             VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
164             &deviceFeatures2,                     // const void* pNext;
165             0u,                                   // VkDeviceCreateFlags flags;
166             1,                                    // uint32_t queueCreateInfoCount;
167             &queueCreateInfo,                     // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
168             0u,                                   // uint32_t enabledLayerCount;
169             nullptr,                              // const char* const* ppEnabledLayerNames;
170             0u,                                   // uint32_t enabledExtensionCount;
171             nullptr,                              // const char* const* ppEnabledExtensionNames;
172             nullptr                               // const VkPhysicalDeviceFeatures* pEnabledFeatures;
173         };
174 
175         m_logicalDevice = createCustomDevice(useValidation, platformInterface, instance, instanceInterface,
176                                              physicalDevice, &deviceCreateInfo);
177     }
178 
getDevice() const179     VkDevice getDevice() const
180     {
181         return *m_logicalDevice;
182     }
183 };
184 
185 class FakeInstanceInterface : public InstanceDriver
186 {
187     const InstanceInterface &m_instanceInterface;
188 
189 public:
FakeInstanceInterface(Context & ctx)190     FakeInstanceInterface(Context &ctx)
191         : InstanceDriver(ctx.getPlatformInterface(), ctx.getInstance())
192         , m_instanceInterface(ctx.getInstanceInterface())
193     {
194     }
195 
getPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures2 * pFeatures) const196     virtual void getPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
197                                             VkPhysicalDeviceFeatures2 *pFeatures) const override
198     {
199         DE_ASSERT(pFeatures);
200 
201         InstanceDriver::getPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
202 
203         auto pBaseStructure = reinterpret_cast<VkBaseOutStructure *>(pFeatures)->pNext;
204         while (pBaseStructure)
205         {
206             if (pBaseStructure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT)
207             {
208                 const VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures{
209                     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT, // VkStructureType sType;
210                     nullptr,                                              // void* pNext;
211                     VK_TRUE,                                              // VkBool32 deviceFault;
212                     VK_TRUE                                               // VkBool32 deviceFaultVendorBinary;
213                 };
214                 *(VkPhysicalDeviceFaultFeaturesEXT *)pBaseStructure = deviceFaultFeatures;
215                 break;
216             }
217             pBaseStructure = pBaseStructure->pNext;
218         }
219     }
220 };
221 
222 class FakeDeviceInterface : public DeviceDriver
223 {
224 public:
FakeDeviceInterface(Context & ctx)225     FakeDeviceInterface(Context &ctx)
226         : DeviceDriver(ctx.getPlatformInterface(), ctx.getInstance(), ctx.getDevice(), ctx.getUsedApiVersion(),
227                        ctx.getTestContext().getCommandLine())
228     {
229     }
230 
231     struct Header : VkDeviceFaultVendorBinaryHeaderVersionOneEXT
232     {
233         char applicationName[32];
234         char engineName[32];
Headervkt::postmortem::__anon370c952c0111::FakeDeviceInterface::Header235         Header()
236         {
237             headerSize    = sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT);
238             headerVersion = VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT;
239             vendorID      = 0x9876;
240             deviceID      = 0x5432;
241             driverVersion = VK_MAKE_VERSION(3, 4, 5);
242             deMemcpy(pipelineCacheUUID, this, sizeof(pipelineCacheUUID));
243             applicationNameOffset = uint32_t(sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT));
244             applicationVersion    = VK_MAKE_API_VERSION(1, 7, 3, 11);
245             engineNameOffset      = uint32_t(applicationNameOffset + sizeof(applicationName));
246 
247             strcpy(applicationName, "application.exe");
248             strcpy(engineName, "driver.so.3.4.5");
249         }
250     };
251 
getDeviceFaultInfoEXT(VkDevice,VkDeviceFaultCountsEXT * pFaultCounts,VkDeviceFaultInfoEXT * pFaultInfo) const252     virtual VkResult getDeviceFaultInfoEXT(VkDevice, VkDeviceFaultCountsEXT *pFaultCounts,
253                                            VkDeviceFaultInfoEXT *pFaultInfo) const override
254     {
255         static std::vector<VkDeviceFaultAddressInfoEXT> addressInfos;
256         static std::vector<VkDeviceFaultVendorInfoEXT> vendorInfos;
257         static VkDeviceFaultAddressTypeEXT addressTypes[]{
258             VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT,
259             VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT,
260             VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT,
261             VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT,
262             VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT,
263             VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT,
264             VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT,
265         };
266         static VkDeviceSize addressPrecisions[]{2, 4, 8, 16};
267         static uint64_t vendorFaultCodes[]{0x11223344, 0x22334455, 0xAABBCCDD, 0xCCDDEEFF};
268         static Header vendorBinaryData;
269 
270         if (DE_NULL == pFaultInfo)
271         {
272             if (DE_NULL == pFaultCounts)
273                 return VK_ERROR_UNKNOWN;
274 
275             DE_ASSERT(pFaultCounts->sType == VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT);
276             DE_ASSERT(pFaultCounts->pNext == nullptr);
277 
278             pFaultCounts->vendorBinarySize = sizeof(Header);
279             pFaultCounts->vendorInfoCount  = 2;
280             pFaultCounts->addressInfoCount = 2;
281         }
282         else
283         {
284             DE_ASSERT(pFaultCounts);
285             DE_ASSERT(pFaultCounts->sType == VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT);
286             DE_ASSERT(pFaultCounts->pNext == nullptr);
287             DE_ASSERT(pFaultInfo->sType == VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT);
288             DE_ASSERT(pFaultInfo->pNext == nullptr);
289 
290             if (pFaultCounts->addressInfoCount && pFaultInfo->pAddressInfos)
291             {
292                 VkDeviceAddress deviceAddress = 1024;
293                 addressInfos.resize(pFaultCounts->addressInfoCount);
294                 for (uint32_t i = 0; i < pFaultCounts->addressInfoCount; ++i)
295                 {
296                     VkDeviceFaultAddressInfoEXT &info = addressInfos[i];
297                     info.addressType                  = addressTypes[i % ARRAY_LENGTH(addressTypes)];
298                     info.addressPrecision             = addressPrecisions[i % ARRAY_LENGTH(addressPrecisions)];
299                     info.reportedAddress              = deviceAddress;
300                     deviceAddress <<= 1;
301 
302                     pFaultInfo->pAddressInfos[i] = info;
303                 }
304             }
305 
306             if (pFaultCounts->vendorInfoCount && pFaultInfo->pVendorInfos)
307             {
308                 vendorInfos.resize(pFaultCounts->vendorInfoCount);
309                 for (uint32_t i = 0; i < pFaultCounts->vendorInfoCount; ++i)
310                 {
311                     VkDeviceFaultVendorInfoEXT &info = vendorInfos[i];
312                     info.vendorFaultCode             = vendorFaultCodes[i % ARRAY_LENGTH(vendorFaultCodes)];
313                     info.vendorFaultData             = (i + 1) % ARRAY_LENGTH(vendorFaultCodes);
314                     deMemset(info.description, 0, sizeof(info.description));
315 
316                     std::stringstream s;
317                     s << "VendorFaultDescription" << info.vendorFaultData;
318                     s.sync();
319                     const auto &str = s.str();
320                     deMemcpy(info.description, str.c_str(), str.length());
321 
322                     pFaultInfo->pVendorInfos[i] = info;
323                 }
324             }
325 
326             if (pFaultCounts->vendorBinarySize && pFaultInfo->pVendorBinaryData)
327             {
328                 DE_ASSERT(pFaultCounts->vendorBinarySize >= sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT));
329                 deMemcpy(pFaultInfo->pVendorBinaryData, &vendorBinaryData,
330                          deMaxu32(sizeof(Header), uint32_t(pFaultCounts->vendorBinarySize)));
331             }
332         }
333 
334         return VK_SUCCESS;
335     }
336 };
337 
338 class FakeContext
339 {
340     FakeDeviceInterface m_deviceInterface;
341     FakeInstanceInterface m_instanceInterface;
342 
343 public:
FakeContext(Context & ctx)344     FakeContext(Context &ctx) : m_deviceInterface(ctx), m_instanceInterface(ctx)
345     {
346     }
347 
getDeviceInterface() const348     const DeviceInterface &getDeviceInterface() const
349     {
350         return m_deviceInterface;
351     }
getInstanceInterface() const352     const InstanceInterface &getInstanceInterface() const
353     {
354         return m_instanceInterface;
355     }
356 };
357 
checkSupport(Context & context) const358 void DeviceFaultCase::checkSupport(Context &context) const
359 {
360     FakeContext fakeContext(context);
361     VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
362     const InstanceInterface &instanceInterface =
363         (m_params.type == TestType::Real) ? context.getInstanceInterface() : fakeContext.getInstanceInterface();
364 
365     context.requireInstanceFunctionality(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
366 
367     if (m_params.type == TestType::Real)
368     {
369         context.requireDeviceFunctionality(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
370     }
371 
372     VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures{};
373     deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
374 
375     VkPhysicalDeviceFeatures2 deviceFeatures2{};
376     deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
377     deviceFeatures2.pNext = &deviceFaultFeatures;
378 
379     instanceInterface.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
380 
381     if (VK_FALSE == deviceFaultFeatures.deviceFault)
382         TCU_THROW(NotSupportedError, "VK_EXT_device_fault extension is not supported by device");
383 }
384 
iterate(void)385 TestStatus DeviceFaultCustomInstance::iterate(void)
386 {
387     CustomDevice customDevice(m_context);
388     const VkDevice device = customDevice.getDevice();
389     return (device != DE_NULL) ? TestStatus::pass("") : TestStatus::fail("");
390 }
391 
log(const std::vector<VkDeviceFaultAddressInfoEXT> & addressInfos,const std::vector<VkDeviceFaultVendorInfoEXT> & vendorInfos,const std::vector<uint8_t> & vendorBinaryData) const392 void DeviceFaultInstance::log(const std::vector<VkDeviceFaultAddressInfoEXT> &addressInfos,
393                               const std::vector<VkDeviceFaultVendorInfoEXT> &vendorInfos,
394                               const std::vector<uint8_t> &vendorBinaryData) const
395 {
396     const char *nl = "\n";
397     uint32_t cnt   = 0;
398     TestLog &log   = m_context.getTestContext().getLog();
399 
400     if (addressInfos.size())
401     {
402         log << TestLog::Section("addressInfos", "");
403         auto msg = log << TestLog::Message;
404         cnt      = 0;
405         for (const auto &addressInfo : addressInfos)
406         {
407             if (cnt++)
408                 msg << nl;
409             msg << addressInfo;
410         }
411         msg << TestLog::EndMessage << TestLog::EndSection;
412     }
413 
414     if (vendorInfos.size())
415     {
416         log << TestLog::Section("vendorInfos", "");
417         auto msg = log << TestLog::Message;
418         cnt      = 0;
419         for (const auto &vendorInfo : vendorInfos)
420         {
421             if (cnt++)
422                 msg << nl;
423             msg << vendorInfo;
424         }
425         msg << TestLog::EndMessage << TestLog::EndSection;
426     }
427 
428     if (vendorBinaryData.size())
429     {
430         DE_ASSERT(vendorBinaryData.size() >= sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT));
431 
432         log << TestLog::Section("vendorBinaryData", "");
433         auto msg     = log << TestLog::Message;
434         auto pHeader = reinterpret_cast<VkDeviceFaultVendorBinaryHeaderVersionOneEXT const *>(vendorBinaryData.data());
435         msg << *pHeader;
436         msg << TestLog::EndMessage << TestLog::EndSection;
437     }
438 }
439 
iterate(void)440 TestStatus DeviceFaultInstance::iterate(void)
441 {
442     FakeContext fakeContext(m_context);
443     const VkDevice device                 = m_context.getDevice();
444     const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
445     const DeviceInterface &deviceInterface =
446         (m_params.type == TestType::Fake) ? fakeContext.getDeviceInterface() : m_context.getDeviceInterface();
447     const InstanceInterface &instanceInterface =
448         (m_params.type == TestType::Fake) ? fakeContext.getInstanceInterface() : m_context.getInstanceInterface();
449 
450     VkDeviceFaultCountsEXT fc{};
451     fc.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
452     fc.pNext = nullptr;
453     deviceInterface.getDeviceFaultInfoEXT(device, &fc, nullptr);
454 
455     const uint32_t vendorBinarySize = std::min(uint32_t(fc.vendorBinarySize), std::numeric_limits<uint32_t>::max());
456 
457     VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures{};
458     deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
459 
460     VkPhysicalDeviceFeatures2 deviceFeatures2{};
461     deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
462     deviceFeatures2.pNext = &deviceFaultFeatures;
463 
464     instanceInterface.getPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
465 
466     fc.vendorBinarySize = deviceFaultFeatures.deviceFaultVendorBinary ? vendorBinarySize : 0;
467 
468     std::vector<VkDeviceFaultAddressInfoEXT> addressInfos(fc.addressInfoCount);
469     std::vector<VkDeviceFaultVendorInfoEXT> vendorInfos(fc.vendorInfoCount);
470     std::vector<uint8_t> vendorBinaryData(vendorBinarySize);
471 
472     VkDeviceFaultInfoEXT fi{};
473     fi.sType             = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
474     fi.pNext             = nullptr;
475     fi.pAddressInfos     = addressInfos.data();
476     fi.pVendorInfos      = vendorInfos.data();
477     fi.pVendorBinaryData = deviceFaultFeatures.deviceFaultVendorBinary ? vendorBinaryData.data() : nullptr;
478 
479     const VkResult result = deviceInterface.getDeviceFaultInfoEXT(device, &fc, &fi);
480 
481     log(addressInfos, vendorInfos, vendorBinaryData);
482 
483     return (result == VK_SUCCESS) ? TestStatus::pass("") : TestStatus::fail("");
484 }
485 
486 } // namespace
487 
createDeviceFaultTests(tcu::TestContext & testCtx)488 tcu::TestCaseGroup *createDeviceFaultTests(tcu::TestContext &testCtx)
489 {
490     TestParams p;
491     struct
492     {
493         TestType type;
494         const char *name;
495     } const types[] = {{TestType::Real, "real"}, {TestType::Fake, "fake"}, {TestType::CustomDevice, "custom_device"}};
496 
497     auto rootGroup = new TestCaseGroup(testCtx, "device_fault");
498     for (const auto &type : types)
499     {
500         p.type = type.type;
501         rootGroup->addChild(new DeviceFaultCase(testCtx, type.name, p));
502     }
503     return rootGroup;
504 }
505 
506 } // namespace postmortem
507 } // namespace vkt
508