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:
parent
c60b19a8ba
commit
6425afc548
|
@ -94,6 +94,7 @@ set(NEO_CORE_OS_INTERFACE_WDDM
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/wddm/set_gmm_input_args_${DRIVER_MODEL}.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wddm/max_mem_alloc_size_${DRIVER_MODEL}.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wddm/helper_${DRIVER_MODEL}.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wddm/is_readonly_memory_${DRIVER_MODEL}.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wddm/skip_resource_cleanup_${DRIVER_MODEL}.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}${BRANCH_DIR_SUFFIX}map_tile_instanced_allocation_${DRIVER_MODEL}.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wddm/wddm.cpp
|
||||
|
|
|
@ -175,5 +175,8 @@ CONFIGRET cmGetDeviceInterfaceList(LPGUID interfaceClassGuid, DEVINSTID_W pDevic
|
|||
return CM_Get_Device_Interface_List(interfaceClassGuid, pDeviceID, buffer, bufferLen, ulFlags);
|
||||
}
|
||||
|
||||
SIZE_T virtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) {
|
||||
return VirtualQuery(lpAddress, lpBuffer, dwLength);
|
||||
}
|
||||
} // namespace SysCalls
|
||||
} // namespace NEO
|
||||
|
|
|
@ -56,7 +56,7 @@ HANDLE createFile(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
|||
BOOL deviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);
|
||||
CONFIGRET cmGetDeviceInterfaceListSize(PULONG pulLen, LPGUID interfaceClassGuid, DEVINSTID_W pDeviceID, ULONG ulFlags);
|
||||
CONFIGRET cmGetDeviceInterfaceList(LPGUID interfaceClassGuid, DEVINSTID_W pDeviceID, PZZWSTR buffer, ULONG bufferLen, ULONG ulFlags);
|
||||
|
||||
SIZE_T virtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
|
||||
} // namespace SysCalls
|
||||
|
||||
} // namespace NEO
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/os_interface/windows/wddm/wddm.h"
|
||||
|
||||
namespace NEO {
|
||||
bool Wddm::isReadOnlyMemory(const void *ptr) {
|
||||
return false;
|
||||
}
|
||||
} // namespace NEO
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "shared/source/os_interface/windows/sys_calls.h"
|
||||
#include "shared/source/os_interface/windows/wddm/wddm.h"
|
||||
|
||||
namespace NEO {
|
||||
|
||||
bool Wddm::isReadOnlyMemory(const void *ptr) {
|
||||
if (ptr) {
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
SysCalls::virtualQuery(ptr, &info, sizeof(info));
|
||||
return info.Protect & PAGE_READONLY;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace NEO
|
|
@ -658,6 +658,12 @@ NTSTATUS Wddm::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKM
|
|||
createAllocation.hDevice = device;
|
||||
|
||||
status = getGdi()->createAllocation2(&createAllocation);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (isReadOnlyMemory(alignedCpuPtr)) {
|
||||
createAllocation.Flags.ReadOnly = true;
|
||||
status = getGdi()->createAllocation2(&createAllocation);
|
||||
}
|
||||
}
|
||||
if (status != STATUS_SUCCESS) {
|
||||
DEBUG_BREAK_IF(true);
|
||||
return status;
|
||||
|
@ -758,6 +764,13 @@ NTSTATUS Wddm::createAllocationsAndMapGpuVa(OsHandleStorage &osHandles) {
|
|||
while (status == STATUS_UNSUCCESSFUL) {
|
||||
status = getGdi()->createAllocation2(&createAllocation);
|
||||
|
||||
if (status != STATUS_SUCCESS) {
|
||||
if (isReadOnlyMemory(allocationInfo[0].pSystemMem)) {
|
||||
createAllocation.Flags.ReadOnly = true;
|
||||
status = getGdi()->createAllocation2(&createAllocation);
|
||||
}
|
||||
}
|
||||
|
||||
if (status != STATUS_SUCCESS) {
|
||||
PRINT_DEBUG_STRING(debugManager.flags.PrintDebugMessages.get(), stderr, "%s status: %d", __FUNCTION__, status);
|
||||
DEBUG_BREAK_IF(status != STATUS_GRAPHICS_NO_VIDEO_MEMORY);
|
||||
|
@ -1370,5 +1383,4 @@ void Wddm::setNewResourceBoundToPageTable() {
|
|||
}
|
||||
this->forEachContextWithinWddm([](const EngineControl &engine) { engine.osContext->setNewResourceBound(); });
|
||||
}
|
||||
|
||||
} // namespace NEO
|
||||
|
|
|
@ -244,6 +244,7 @@ class Wddm : public DriverModel {
|
|||
void setNewResourceBoundToPageTable();
|
||||
void setProcessPowerThrottling();
|
||||
void setThreadPriority();
|
||||
bool isReadOnlyMemory(const void *ptr);
|
||||
|
||||
GMM_GFX_PARTITIONING gfxPartition{};
|
||||
ADAPTER_BDF adapterBDF{};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)) {}
|
||||
|
|
|
@ -959,5 +959,4 @@ TEST_F(WddmTests, whenInitializeFailureThenInitOsInterfaceWddmFails) {
|
|||
|
||||
EXPECT_FALSE(rootDeviceEnvironment->initOsInterface(std::move(hwDeviceId), 0u));
|
||||
}
|
||||
|
||||
} // namespace NEO
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue