From 6425afc548faf895d1fe585d94f522cf8ae5544e Mon Sep 17 00:00:00 2001 From: Igor Venevtsev Date: Fri, 19 Apr 2024 09:51:16 +0000 Subject: [PATCH] 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 --- .../os_interface/windows/CMakeLists.txt | 1 + .../source/os_interface/windows/sys_calls.cpp | 3 + .../source/os_interface/windows/sys_calls.h | 2 +- .../wddm/is_readonly_memory_drm_or_wddm.cpp | 14 ++++ .../windows/wddm/is_readonly_memory_wddm.cpp | 21 ++++++ .../source/os_interface/windows/wddm/wddm.cpp | 14 +++- .../source/os_interface/windows/wddm/wddm.h | 1 + shared/test/common/mock_gdi/mock_gdi.cpp | 30 ++++++++- shared/test/common/mock_gdi/mock_gdi.h | 4 +- .../test/common/mock_gdi/mock_os_library.cpp | 9 ++- shared/test/common/mocks/mock_wddm.h | 1 + .../os_interface/windows/gdi_dll_fixture.h | 6 +- .../common/os_interface/windows/sys_calls.cpp | 6 ++ ..._device_address_space_drm_or_wddm_test.cpp | 13 +++- .../os_interface/windows/wddm_tests.cpp | 1 - .../windows/wddm_windows_tests.cpp | 67 +++++++++++++++++++ 16 files changed, 184 insertions(+), 9 deletions(-) create mode 100644 shared/source/os_interface/windows/wddm/is_readonly_memory_drm_or_wddm.cpp create mode 100644 shared/source/os_interface/windows/wddm/is_readonly_memory_wddm.cpp diff --git a/shared/source/os_interface/windows/CMakeLists.txt b/shared/source/os_interface/windows/CMakeLists.txt index aa03921187..7e61079407 100644 --- a/shared/source/os_interface/windows/CMakeLists.txt +++ b/shared/source/os_interface/windows/CMakeLists.txt @@ -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 diff --git a/shared/source/os_interface/windows/sys_calls.cpp b/shared/source/os_interface/windows/sys_calls.cpp index 49dfc2cfcd..f4f6f04b8f 100644 --- a/shared/source/os_interface/windows/sys_calls.cpp +++ b/shared/source/os_interface/windows/sys_calls.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 diff --git a/shared/source/os_interface/windows/sys_calls.h b/shared/source/os_interface/windows/sys_calls.h index 7728eeeef5..f49f3b8cac 100644 --- a/shared/source/os_interface/windows/sys_calls.h +++ b/shared/source/os_interface/windows/sys_calls.h @@ -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 diff --git a/shared/source/os_interface/windows/wddm/is_readonly_memory_drm_or_wddm.cpp b/shared/source/os_interface/windows/wddm/is_readonly_memory_drm_or_wddm.cpp new file mode 100644 index 0000000000..afa33a18b2 --- /dev/null +++ b/shared/source/os_interface/windows/wddm/is_readonly_memory_drm_or_wddm.cpp @@ -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 diff --git a/shared/source/os_interface/windows/wddm/is_readonly_memory_wddm.cpp b/shared/source/os_interface/windows/wddm/is_readonly_memory_wddm.cpp new file mode 100644 index 0000000000..9e570733e9 --- /dev/null +++ b/shared/source/os_interface/windows/wddm/is_readonly_memory_wddm.cpp @@ -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 diff --git a/shared/source/os_interface/windows/wddm/wddm.cpp b/shared/source/os_interface/windows/wddm/wddm.cpp index 0e641a453c..1b69c024b2 100644 --- a/shared/source/os_interface/windows/wddm/wddm.cpp +++ b/shared/source/os_interface/windows/wddm/wddm.cpp @@ -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 diff --git a/shared/source/os_interface/windows/wddm/wddm.h b/shared/source/os_interface/windows/wddm/wddm.h index 8a811a3e8e..fb5ddef8eb 100644 --- a/shared/source/os_interface/windows/wddm/wddm.h +++ b/shared/source/os_interface/windows/wddm/wddm.h @@ -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{}; diff --git a/shared/test/common/mock_gdi/mock_gdi.cpp b/shared/test/common/mock_gdi/mock_gdi.cpp index 7901d8db91..a5f80e0391 100644 --- a/shared/test/common/mock_gdi/mock_gdi.cpp +++ b/shared/test/common/mock_gdi/mock_gdi.cpp @@ -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; diff --git a/shared/test/common/mock_gdi/mock_gdi.h b/shared/test/common/mock_gdi/mock_gdi.h index a71337fbb2..bb109aaa67 100644 --- a/shared/test/common/mock_gdi/mock_gdi.h +++ b/shared/test/common/mock_gdi/mock_gdi.h @@ -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); diff --git a/shared/test/common/mock_gdi/mock_os_library.cpp b/shared/test/common/mock_gdi/mock_os_library.cpp index 9d93a3e0a3..40ece6956a 100644 --- a/shared/test/common/mock_gdi/mock_os_library.cpp +++ b/shared/test/common/mock_gdi/mock_os_library.cpp @@ -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(mockD3DKMTUnregisterTrimNotification); } - + if (procName == "getCreateAllocation2ReadOnlyFailConfig") { + return reinterpret_cast(getCreateAllocation2ReadOnlyFailConfig); + } + if (procName == "setCreateAllocation2ReadOnlyFailConfig") { + return reinterpret_cast(setCreateAllocation2ReadOnlyFailConfig); + } return nullptr; } diff --git a/shared/test/common/mocks/mock_wddm.h b/shared/test/common/mocks/mock_wddm.h index 24b2d4d6c4..6afa599386 100644 --- a/shared/test/common/mocks/mock_wddm.h +++ b/shared/test/common/mocks/mock_wddm.h @@ -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; diff --git a/shared/test/common/os_interface/windows/gdi_dll_fixture.h b/shared/test/common/os_interface/windows/gdi_dll_fixture.h index 95dc11eb86..f4c308c3ba 100644 --- a/shared/test/common/os_interface/windows/gdi_dll_fixture.h +++ b/shared/test/common/os_interface/windows/gdi_dll_fixture.h @@ -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(mockGdiDll->getProcAddress("setAdapterBDF")); setMockDeviceExecutionStateFcn = reinterpret_cast(mockGdiDll->getProcAddress("setMockDeviceExecutionState")); setMockGetDeviceStateReturnValueFcn = reinterpret_cast(mockGdiDll->getProcAddress("setMockGetDeviceStateReturnValue")); + getCreateAllocation2ReadOnlyFailConfigFcn = reinterpret_cast(mockGdiDll->getProcAddress("getCreateAllocation2ReadOnlyFailConfig")); + setCreateAllocation2ReadOnlyFailConfigFcn = reinterpret_cast(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; }; diff --git a/shared/test/common/os_interface/windows/sys_calls.cpp b/shared/test/common/os_interface/windows/sys_calls.cpp index 5e6b3a49d0..162358a420 100644 --- a/shared/test/common/os_interface/windows/sys_calls.cpp +++ b/shared/test/common/os_interface/windows/sys_calls.cpp @@ -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() { diff --git a/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp b/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp index 139d840631..683eb55893 100644 --- a/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp +++ b/shared/test/unit_test/os_interface/wddm_linux/configure_device_address_space_drm_or_wddm_test.cpp @@ -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 deviceTime) : NEO::OSTimeLinux(osInterface, std::move(deviceTime)) {} diff --git a/shared/test/unit_test/os_interface/windows/wddm_tests.cpp b/shared/test/unit_test/os_interface/windows/wddm_tests.cpp index 776d72faff..57a40207ef 100644 --- a/shared/test/unit_test/os_interface/windows/wddm_tests.cpp +++ b/shared/test/unit_test/os_interface/windows/wddm_tests.cpp @@ -959,5 +959,4 @@ TEST_F(WddmTests, whenInitializeFailureThenInitOsInterfaceWddmFails) { EXPECT_FALSE(rootDeviceEnvironment->initOsInterface(std::move(hwDeviceId), 0u)); } - } // namespace NEO diff --git a/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp b/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp index bd1a82ee81..eca845e455 100644 --- a/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp +++ b/shared/test/unit_test/os_interface/windows/wddm_windows_tests.cpp @@ -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 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); } \ No newline at end of file