fix: correct flags for creating allocation with existing system memory

on Windows setup ReadOnly flag, it makes there is no ProbeForWrite call within
CreateAllocation2 function call

it doesn't force read-only access from GPU perspective, that access it
defined in MapGpuVa function

Related-To: NEO-12986, HSD-15016952776
Signed-off-by: Mateusz Jablonski <mateusz.jablonski@intel.com>
This commit is contained in:
Mateusz Jablonski
2025-01-30 19:43:45 +00:00
committed by Compute-Runtime-Automation
parent aace15d6bc
commit a924761ed1
15 changed files with 91 additions and 146 deletions

View File

@@ -97,7 +97,6 @@ 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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2022 Intel Corporation
* Copyright (C) 2021-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -12,4 +12,7 @@ namespace NEO {
NTSTATUS Wddm::createNTHandle(const D3DKMT_HANDLE *resourceHandle, HANDLE *ntHandle) {
return getGdi()->shareObjects(1, resourceHandle, nullptr, SHARED_ALLOCATION_WRITE, ntHandle);
}
bool Wddm::getReadOnlyFlagValue(const void *alignedCpuPtr) const {
return false;
}
} // namespace NEO

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Intel Corporation
* Copyright (C) 2021-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -16,4 +16,8 @@ NTSTATUS Wddm::createNTHandle(const D3DKMT_HANDLE *resourceHandle, HANDLE *ntHan
return getGdi()->shareObjects(1, resourceHandle, &objAttr, SHARED_ALLOCATION_WRITE, ntHandle);
}
bool Wddm::getReadOnlyFlagValue(const void *alignedCpuPtr) const {
return alignedCpuPtr != nullptr;
}
} // namespace NEO

View File

@@ -1,14 +0,0 @@
/*
* Copyright (C) 2024-2025 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

View File

@@ -1,21 +0,0 @@
/*
* Copyright (C) 2024-2025 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

View File

@@ -665,6 +665,7 @@ NTSTATUS Wddm::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKM
createAllocation.Flags.CreateShared = outSharedHandle ? TRUE : FALSE;
createAllocation.Flags.NtSecuritySharing = outSharedHandle ? TRUE : FALSE;
createAllocation.Flags.CreateResource = outSharedHandle ? TRUE : FALSE;
createAllocation.Flags.ReadOnly = getReadOnlyFlagValue(alignedCpuPtr);
createAllocation.pAllocationInfo2 = &allocationInfo;
createAllocation.hDevice = device;
@@ -677,12 +678,6 @@ NTSTATUS Wddm::createAllocation(const void *alignedCpuPtr, const Gmm *gmm, D3DKM
}
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;
@@ -777,19 +772,13 @@ NTSTATUS Wddm::createAllocationsAndMapGpuVa(OsHandleStorage &osHandles) {
createAllocation.Flags.CreateShared = FALSE;
createAllocation.Flags.RestrictSharedAccess = FALSE;
createAllocation.Flags.CreateResource = FALSE;
createAllocation.Flags.ReadOnly = getReadOnlyFlagValue(allocationInfo[0].pSystemMem);
createAllocation.pAllocationInfo2 = allocationInfo;
createAllocation.hDevice = device;
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);

View File

@@ -257,7 +257,7 @@ class Wddm : public DriverModel {
void setNewResourceBoundToPageTable();
void setProcessPowerThrottling();
void setThreadPriority();
bool isReadOnlyMemory(const void *ptr);
bool getReadOnlyFlagValue(const void *alignedCpuPtr) const;
GMM_GFX_PARTITIONING gfxPartition{};
ADAPTER_BDF adapterBDF{};

View File

@@ -156,20 +156,19 @@ inline void *getStaticStorage(uint32_t slot) {
return ptrOffset(baseAddress, slot * singleStorageSize);
}
static bool createAllocation2FailOnReadOnlyAllocation = false;
static bool createAllocation2ReadOnlyFlagWasPassed = false;
static D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{};
static bool captureCreateAllocationFlags = false;
static uint32_t createAllocation2NumCalled = 0;
void setCreateAllocation2ReadOnlyFailConfig(bool fail) {
createAllocation2FailOnReadOnlyAllocation = fail;
createAllocation2ReadOnlyFlagWasPassed = false;
void setCapturingCreateAllocationFlags() {
captureCreateAllocationFlags = true;
createAllocation2NumCalled = 0;
}
void getCreateAllocation2ReadOnlyFailConfig(bool &readOnlyFlagWasPassed, uint32_t &numCalled) {
readOnlyFlagWasPassed = createAllocation2ReadOnlyFlagWasPassed;
void getCapturedCreateAllocationFlags(D3DKMT_CREATEALLOCATIONFLAGS &capturedCreateAllocationFlags, uint32_t &numCalled) {
capturedCreateAllocationFlags = createAllocationFlags;
numCalled = createAllocation2NumCalled;
setCreateAllocation2ReadOnlyFailConfig(false);
captureCreateAllocationFlags = false;
}
NTSTATUS __stdcall mockD3DKMTCreateAllocation2(IN OUT D3DKMT_CREATEALLOCATION *allocation) {
@@ -187,14 +186,10 @@ NTSTATUS __stdcall mockD3DKMTCreateAllocation2(IN OUT D3DKMT_CREATEALLOCATION *a
return STATUS_INVALID_PARAMETER;
}
if (createAllocation2FailOnReadOnlyAllocation) {
if (captureCreateAllocationFlags) {
createAllocationFlags = pallocation.Flags;
createAllocation2NumCalled++;
if (pallocation.Flags.ReadOnly) {
createAllocation2ReadOnlyFlagWasPassed = true;
return STATUS_SUCCESS;
} else {
return STATUS_GRAPHICS_NO_VIDEO_MEMORY;
}
}
numOfAllocations = allocation->NumAllocations;

View File

@@ -109,5 +109,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);
void setCapturingCreateAllocationFlags();
void getCapturedCreateAllocationFlags(D3DKMT_CREATEALLOCATIONFLAGS &capturedCreateAllocationFlags, uint32_t &numCalled);

View File

@@ -253,11 +253,11 @@ 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 == "setCapturingCreateAllocationFlags") {
return reinterpret_cast<void *>(setCapturingCreateAllocationFlags);
}
if (procName == "setCreateAllocation2ReadOnlyFailConfig") {
return reinterpret_cast<void *>(setCreateAllocation2ReadOnlyFailConfig);
if (procName == "getCapturedCreateAllocationFlags") {
return reinterpret_cast<void *>(getCapturedCreateAllocationFlags);
}
return nullptr;
}

View File

@@ -47,13 +47,13 @@ class WddmMock : public Wddm {
using Wddm::featureTable;
using Wddm::forceEvictOnlyIfNecessary;
using Wddm::getDeviceState;
using Wddm::getReadOnlyFlagValue;
using Wddm::getSystemInfo;
using Wddm::gfxFeatureTable;
using Wddm::gfxPlatform;
using Wddm::gfxWorkaroundTable;
using Wddm::gmmMemory;
using Wddm::hwDeviceId;
using Wddm::isReadOnlyMemory;
using Wddm::mapGpuVirtualAddress;
using Wddm::minAddress;
using Wddm::pagingFenceAddress;

View File

@@ -61,8 +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"));
getCapturedCreateAllocationFlagsFcn = reinterpret_cast<decltype(&getCapturedCreateAllocationFlags)>(mockGdiDll->getProcAddress("getCapturedCreateAllocationFlags"));
setCapturingCreateAllocationFlagsFcn = reinterpret_cast<decltype(&setCapturingCreateAllocationFlags)>(mockGdiDll->getProcAddress("setCapturingCreateAllocationFlags"));
setMockLastDestroyedResHandleFcn((D3DKMT_HANDLE)0);
*getDestroySynchronizationObjectDataFcn() = {};
*getCreateSynchronizationObject2FailCallFcn() = false;
@@ -111,6 +111,6 @@ struct GdiDllFixture {
decltype(&setAdapterBDF) setAdapterBDFFcn = nullptr;
decltype(&setMockDeviceExecutionState) setMockDeviceExecutionStateFcn = nullptr;
decltype(&setMockGetDeviceStateReturnValue) setMockGetDeviceStateReturnValueFcn = nullptr;
decltype(&getCreateAllocation2ReadOnlyFailConfig) getCreateAllocation2ReadOnlyFailConfigFcn = nullptr;
decltype(&setCreateAllocation2ReadOnlyFailConfig) setCreateAllocation2ReadOnlyFailConfigFcn = nullptr;
decltype(&setCapturingCreateAllocationFlags) setCapturingCreateAllocationFlagsFcn = nullptr;
decltype(&getCapturedCreateAllocationFlags) getCapturedCreateAllocationFlagsFcn = nullptr;
};

View File

@@ -62,10 +62,10 @@ struct MockWddmLinux : NEO::Wddm {
std::vector<void *> validAddressRangeReleases;
using Wddm::featureTable;
using Wddm::getReadOnlyFlagValue;
using Wddm::gfxPartition;
using Wddm::gfxPlatform;
using Wddm::gmmMemory;
using Wddm::isReadOnlyMemory;
};
struct MockGmmMemoryWddmLinux : NEO::GmmMemory {
@@ -796,14 +796,11 @@ TEST_F(WddmLinuxTest, whenCheckedIfResourcesCleanupCanBeSkippedAndDeviceIsLostTh
EXPECT_EQ(1, gdiMockConfig.getDeviceStateClb.callCount);
}
TEST_F(WddmLinuxTest, whenIsReadOnlyMemoryCalledThenCorrectValueReturned) {
EXPECT_FALSE(wddm->isReadOnlyMemory(nullptr));
TEST_F(WddmLinuxTest, whenGettingReadOnlyFlagThenAlwaysReturnFalse) {
void *ptr = reinterpret_cast<void *>(0x1000);
EXPECT_FALSE(wddm->getReadOnlyFlagValue(ptr));
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));
EXPECT_FALSE(wddm->getReadOnlyFlagValue(nullptr));
}
class MockOsTimeLinux : public NEO::OSTimeLinux {

View File

@@ -1000,4 +1000,53 @@ TEST_F(WddmTests, whenInitializeFailureThenInitOsInterfaceWddmFails) {
EXPECT_FALSE(rootDeviceEnvironment->initOsInterface(std::move(hwDeviceId), 0u));
}
TEST_F(WddmTests, givenHostMemoryPassedToCreateAllocationThenAllocationCreatedWithReadOnlyFlagPassed) {
wddm->init();
setCapturingCreateAllocationFlagsFcn();
static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
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));
D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{};
uint32_t createAllocation2NumCalled = 0;
getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled);
EXPECT_EQ(createAllocationFlags.ReadOnly, wddm->getReadOnlyFlagValue(constMem));
EXPECT_EQ(1u, createAllocation2NumCalled);
}
TEST_F(WddmTests, givenHostMemoryPassedToCreateAllocationsAndMapGpuVaThenAllocationCreatedWithReadOnlyFlagPassed) {
wddm->init();
wddm->callBaseMapGpuVa = false;
setCapturingCreateAllocationFlagsFcn();
static const int constMem[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
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));
D3DKMT_CREATEALLOCATIONFLAGS createAllocationFlags{};
uint32_t createAllocation2NumCalled = 0;
getCapturedCreateAllocationFlagsFcn(createAllocationFlags, createAllocation2NumCalled);
EXPECT_EQ(createAllocationFlags.ReadOnly, wddm->getReadOnlyFlagValue(constMem));
EXPECT_EQ(1u, createAllocation2NumCalled);
}
} // namespace NEO

View File

@@ -406,65 +406,9 @@ TEST_F(WddmTestWithMockGdiDll, givenSetThreadPriorityStateEnabledWhenInitWddmThe
EXPECT_EQ(SysCalls::ThreadPriority::AboveNormal, SysCalls::setThreadPriorityLastValue);
}
TEST_F(WddmTestWithMockGdiDll, whenIsReadOnlyMemoryCalledThenCorrectValueReturned) {
EXPECT_FALSE(wddm->isReadOnlyMemory(nullptr));
TEST_F(WddmTestWithMockGdiDll, whenGettingReadOnlyFlagThenReturnTrueOnlyForCpuPointer) {
void *ptr = reinterpret_cast<void *>(0x1000);
EXPECT_TRUE(wddm->getReadOnlyFlagValue(ptr));
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);
EXPECT_FALSE(wddm->getReadOnlyFlagValue(nullptr));
}