fix: properly set ReadOnly flag for D3DKMTCreateAllocation2

This is an OS behavior to have failed an allocation with a
const buffer backing storage (PAGE_READONLY attribute set)
ReadOnly flag allows to create allocation with read-only
backing storage

Related-To: NEO-9664, HSD-16021966023

Signed-off-by: Igor Venevtsev <igor.venevtsev@intel.com>
This commit is contained in:
Igor Venevtsev
2024-04-19 09:51:16 +00:00
committed by Compute-Runtime-Automation
parent c60b19a8ba
commit 6425afc548
16 changed files with 184 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2023 Intel Corporation
* Copyright (C) 2018-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -156,6 +156,22 @@ inline void *getStaticStorage(uint32_t slot) {
return ptrOffset(baseAddress, slot * singleStorageSize);
}
static bool createAllocation2FailOnReadOnlyAllocation = false;
static bool createAllocation2ReadOnlyFlagWasPassed = false;
static uint32_t createAllocation2NumCalled = 0;
void setCreateAllocation2ReadOnlyFailConfig(bool fail) {
createAllocation2FailOnReadOnlyAllocation = fail;
createAllocation2ReadOnlyFlagWasPassed = false;
createAllocation2NumCalled = 0;
}
void getCreateAllocation2ReadOnlyFailConfig(bool &readOnlyFlagWasPassed, uint32_t &numCalled) {
readOnlyFlagWasPassed = createAllocation2ReadOnlyFlagWasPassed;
numCalled = createAllocation2NumCalled;
setCreateAllocation2ReadOnlyFailConfig(false);
}
NTSTATUS __stdcall mockD3DKMTCreateAllocation2(IN OUT D3DKMT_CREATEALLOCATION *allocation) {
D3DDDI_ALLOCATIONINFO2 *allocationInfo;
int numOfAllocations;
@@ -164,11 +180,23 @@ NTSTATUS __stdcall mockD3DKMTCreateAllocation2(IN OUT D3DKMT_CREATEALLOCATION *a
if (allocation == nullptr || allocation->hDevice != DEVICE_HANDLE) {
return STATUS_INVALID_PARAMETER;
}
pallocation = *allocation;
allocationInfo = allocation->pAllocationInfo2;
if (allocationInfo == NULL) {
return STATUS_INVALID_PARAMETER;
}
if (createAllocation2FailOnReadOnlyAllocation) {
createAllocation2NumCalled++;
if (pallocation.Flags.ReadOnly) {
createAllocation2ReadOnlyFlagWasPassed = true;
return STATUS_SUCCESS;
} else {
return STATUS_GRAPHICS_NO_VIDEO_MEMORY;
}
}
numOfAllocations = allocation->NumAllocations;
createResource = allocation->Flags.CreateResource;
globalShare = allocation->Flags.CreateShared;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2023 Intel Corporation
* Copyright (C) 2018-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -107,3 +107,5 @@ void setAdapterBDF(ADAPTER_BDF &adapterBDF);
void setMockDeviceExecutionState(D3DKMT_DEVICEEXECUTION_STATE newState);
void setMockGetDeviceStateReturnValue(NTSTATUS newReturnValue, bool execution);
void initGfxPartition();
void setCreateAllocation2ReadOnlyFailConfig(bool fail);
void getCreateAllocation2ReadOnlyFailConfig(bool &readOnlyFlagWasPassed, uint32_t &numCalled);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2023 Intel Corporation
* Copyright (C) 2022-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -247,7 +247,12 @@ void *MockOsLibrary::getProcAddress(const std::string &procName) {
if (procName == "D3DKMTUnregisterTrimNotification") {
return reinterpret_cast<void *>(mockD3DKMTUnregisterTrimNotification);
}
if (procName == "getCreateAllocation2ReadOnlyFailConfig") {
return reinterpret_cast<void *>(getCreateAllocation2ReadOnlyFailConfig);
}
if (procName == "setCreateAllocation2ReadOnlyFailConfig") {
return reinterpret_cast<void *>(setCreateAllocation2ReadOnlyFailConfig);
}
return nullptr;
}

View File

@@ -46,6 +46,7 @@ class WddmMock : public Wddm {
using Wddm::gfxWorkaroundTable;
using Wddm::gmmMemory;
using Wddm::hwDeviceId;
using Wddm::isReadOnlyMemory;
using Wddm::mapGpuVirtualAddress;
using Wddm::minAddress;
using Wddm::pagingFenceAddress;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2023 Intel Corporation
* Copyright (C) 2018-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -61,6 +61,8 @@ struct GdiDllFixture {
reinterpret_cast<decltype(&setAdapterBDF)>(mockGdiDll->getProcAddress("setAdapterBDF"));
setMockDeviceExecutionStateFcn = reinterpret_cast<decltype(&setMockDeviceExecutionState)>(mockGdiDll->getProcAddress("setMockDeviceExecutionState"));
setMockGetDeviceStateReturnValueFcn = reinterpret_cast<decltype(&setMockGetDeviceStateReturnValue)>(mockGdiDll->getProcAddress("setMockGetDeviceStateReturnValue"));
getCreateAllocation2ReadOnlyFailConfigFcn = reinterpret_cast<decltype(&getCreateAllocation2ReadOnlyFailConfig)>(mockGdiDll->getProcAddress("getCreateAllocation2ReadOnlyFailConfig"));
setCreateAllocation2ReadOnlyFailConfigFcn = reinterpret_cast<decltype(&setCreateAllocation2ReadOnlyFailConfig)>(mockGdiDll->getProcAddress("setCreateAllocation2ReadOnlyFailConfig"));
setMockLastDestroyedResHandleFcn((D3DKMT_HANDLE)0);
*getDestroySynchronizationObjectDataFcn() = {};
*getCreateSynchronizationObject2FailCallFcn() = false;
@@ -109,4 +111,6 @@ struct GdiDllFixture {
decltype(&setAdapterBDF) setAdapterBDFFcn = nullptr;
decltype(&setMockDeviceExecutionState) setMockDeviceExecutionStateFcn = nullptr;
decltype(&setMockGetDeviceStateReturnValue) setMockGetDeviceStateReturnValueFcn = nullptr;
decltype(&getCreateAllocation2ReadOnlyFailConfig) getCreateAllocation2ReadOnlyFailConfigFcn = nullptr;
decltype(&setCreateAllocation2ReadOnlyFailConfig) setCreateAllocation2ReadOnlyFailConfigFcn = nullptr;
};

View File

@@ -401,6 +401,12 @@ LSTATUS regQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDW
}
return ERROR_FILE_NOT_FOUND;
};
MEMORY_BASIC_INFORMATION virtualQueryMemoryBasicInformation = {};
SIZE_T virtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) {
memcpy_s(lpBuffer, sizeof(MEMORY_BASIC_INFORMATION), &virtualQueryMemoryBasicInformation, sizeof(MEMORY_BASIC_INFORMATION));
return sizeof(MEMORY_BASIC_INFORMATION);
}
} // namespace SysCalls
bool isShutdownInProgress() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2023 Intel Corporation
* Copyright (C) 2021-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -65,6 +65,7 @@ struct MockWddmLinux : NEO::Wddm {
using Wddm::gfxPartition;
using Wddm::gfxPlatform;
using Wddm::gmmMemory;
using Wddm::isReadOnlyMemory;
};
struct MockGmmMemoryWddmLinux : NEO::GmmMemory {
@@ -795,6 +796,16 @@ TEST_F(WddmLinuxTest, whenCheckedIfResourcesCleanupCanBeSkippedAndDeviceIsLostTh
EXPECT_EQ(1, gdiMockConfig.getDeviceStateClb.callCount);
}
TEST_F(WddmLinuxTest, whenIsReadOnlyMemoryCalledThenCorrectValueReturned) {
EXPECT_FALSE(wddm->isReadOnlyMemory(nullptr));
static int mem[10];
EXPECT_FALSE(wddm->isReadOnlyMemory(mem));
static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
EXPECT_FALSE(wddm->isReadOnlyMemory(constMem));
}
class MockOsTimeLinux : public NEO::OSTimeLinux {
public:
MockOsTimeLinux(NEO::OSInterface &osInterface, std::unique_ptr<NEO::DeviceTime> deviceTime) : NEO::OSTimeLinux(osInterface, std::move(deviceTime)) {}

View File

@@ -959,5 +959,4 @@ TEST_F(WddmTests, whenInitializeFailureThenInitOsInterfaceWddmFails) {
EXPECT_FALSE(rootDeviceEnvironment->initOsInterface(std::move(hwDeviceId), 0u));
}
} // namespace NEO

View File

@@ -32,8 +32,12 @@ extern size_t setProcessPowerThrottlingStateCalled;
extern SysCalls::ProcessPowerThrottlingState setProcessPowerThrottlingStateLastValue;
extern size_t setThreadPriorityCalled;
extern SysCalls::ThreadPriority setThreadPriorityLastValue;
extern MEMORY_BASIC_INFORMATION virtualQueryMemoryBasicInformation;
} // namespace SysCalls
extern uint32_t numRootDevicesToEnum;
extern bool gCreateAllocation2FailOnReadOnlyAllocation;
extern bool gCreateAllocation2ReadOnlyFlagWasPassed;
extern uint32_t gCreateAllocation2NumCalled;
std::unique_ptr<HwDeviceIdWddm> createHwDeviceIdFromAdapterLuid(OsEnvironmentWin &osEnvironment, LUID adapterLuid, uint32_t adapterNodeOrdinalIn);
} // namespace NEO
@@ -401,4 +405,67 @@ TEST_F(WddmTestWithMockGdiDll, givenSetThreadPriorityStateEnabledWhenInitWddmThe
wddm->init();
EXPECT_EQ(1u, SysCalls::setThreadPriorityCalled);
EXPECT_EQ(SysCalls::ThreadPriority::AboveNormal, SysCalls::setThreadPriorityLastValue);
}
TEST_F(WddmTestWithMockGdiDll, whenIsReadOnlyMemoryCalledThenCorrectValueReturned) {
EXPECT_FALSE(wddm->isReadOnlyMemory(nullptr));
static int mem[10];
SysCalls::virtualQueryMemoryBasicInformation.Protect = PAGE_READWRITE;
EXPECT_FALSE(wddm->isReadOnlyMemory(mem));
static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
SysCalls::virtualQueryMemoryBasicInformation.Protect = PAGE_READONLY;
EXPECT_TRUE(wddm->isReadOnlyMemory(constMem));
}
TEST_F(WddmTestWithMockGdiDll, givenReadOnlyHostMemoryPassedToCreateAllocationThenAllocationCreatedWithRetryAndReadOnlyFlagPassed) {
wddm->init();
setCreateAllocation2ReadOnlyFailConfigFcn(true);
static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
SysCalls::virtualQueryMemoryBasicInformation.Protect = PAGE_READONLY;
D3DKMT_HANDLE handle, resHandle;
GmmRequirements gmmRequirements{};
Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), constMem, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements);
EXPECT_EQ(STATUS_SUCCESS, wddm->createAllocation(constMem, &gmm, handle, resHandle, nullptr));
bool readOnlyFlagWasPassed = false;
uint32_t createAllocation2NumCalled = 0;
getCreateAllocation2ReadOnlyFailConfigFcn(readOnlyFlagWasPassed, createAllocation2NumCalled);
EXPECT_TRUE(readOnlyFlagWasPassed);
EXPECT_EQ(2u, createAllocation2NumCalled);
}
TEST_F(WddmTestWithMockGdiDll, givenReadOnlyHostMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocationCreatedWithRetryAndReadOnlyFlagPassed) {
wddm->init();
wddm->callBaseMapGpuVa = false;
setCreateAllocation2ReadOnlyFailConfigFcn(true);
static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
SysCalls::virtualQueryMemoryBasicInformation.Protect = PAGE_READONLY;
GmmRequirements gmmRequirements{};
Gmm gmm(executionEnvironment->rootDeviceEnvironments[0]->getGmmHelper(), constMem, 10, 0, GMM_RESOURCE_USAGE_OCL_BUFFER, {}, gmmRequirements);
OsHandleStorage handleStorage;
OsHandleWin osHandle;
auto maxOsContextCount = 1u;
ResidencyData residency(maxOsContextCount);
handleStorage.fragmentCount = 1;
handleStorage.fragmentStorageData[0].cpuPtr = constMem;
handleStorage.fragmentStorageData[0].fragmentSize = 10;
handleStorage.fragmentStorageData[0].freeTheFragment = false;
handleStorage.fragmentStorageData[0].osHandleStorage = &osHandle;
handleStorage.fragmentStorageData[0].residency = &residency;
osHandle.gmm = &gmm;
EXPECT_EQ(STATUS_SUCCESS, wddm->createAllocationsAndMapGpuVa(handleStorage));
bool readOnlyFlagWasPassed = false;
uint32_t createAllocation2NumCalled = 0;
getCreateAllocation2ReadOnlyFailConfigFcn(readOnlyFlagWasPassed, createAllocation2NumCalled);
EXPECT_TRUE(readOnlyFlagWasPassed);
EXPECT_EQ(2u, createAllocation2NumCalled);
}