nvdrv: Add GetTpcMasks2 support and improve memory mapping validation

This commit makes two main changes:

1. Adds support for GetTpcMasks2 (ioctl 0x13) in nvhost_ctrl_gpu:
- Implements new GetTpcMasks2 method to handle TPC mask queries
- Adds IoctlGetTpcMasks structure to store mask parameters
- Returns conservative single TPC configuration for compatibility

2. Enhances memory mapping validation in HostMemory:
- Adds verification check after memory mapping operations
- Improves error handling for direct mapped address enabling
- Adds logging for mapping and direct address failures

Additional changes:
- Updates copyright headers to include citron Emulator Project
- Improves error handling and validation in several paths
- Adds debug logging for TPC mask operations

This improves GPU virtualization support and memory mapping reliability.
This commit is contained in:
Zephyron 2025-02-01 19:48:11 +10:00
parent e8bbdbce42
commit ecc32958ec
No known key found for this signature in database
GPG key ID: 2177ADED8AC966AF
3 changed files with 49 additions and 2 deletions

View file

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#ifdef _WIN32 #ifdef _WIN32
@ -720,10 +721,18 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size); ASSERT(virtual_offset + length <= virtual_size);
ASSERT(host_offset + length <= backing_size); ASSERT(host_offset + length <= backing_size);
if (length == 0 || !virtual_base || !impl) { if (length == 0 || !virtual_base || !impl) {
return; return;
} }
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms); impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
// Verify mapping was successful
if (!impl->IsValidMapping(virtual_offset + virtual_base_offset, length)) {
LOG_CRITICAL(Common_Memory, "Failed to verify memory mapping: virtual_offset={:x}, host_offset={:x}, length={:x}",
virtual_offset, host_offset, length);
}
} }
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) { void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
@ -756,9 +765,18 @@ void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 f
} }
void HostMemory::EnableDirectMappedAddress() { void HostMemory::EnableDirectMappedAddress() {
if (impl) { if (!impl) {
impl->EnableDirectMappedAddress(); LOG_ERROR(Common_Memory, "Implementation not initialized");
return;
}
impl->EnableDirectMappedAddress();
// Only update virtual_size if the direct mapping was successful
if (impl->IsDirectMappingEnabled()) {
virtual_size += reinterpret_cast<uintptr_t>(virtual_base); virtual_size += reinterpret_cast<uintptr_t>(virtual_base);
} else {
LOG_ERROR(Common_Memory, "Failed to enable direct mapped address");
} }
} }

View file

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring> #include <cstring>
@ -45,6 +46,8 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output); return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output);
case 0x1c: case 0x1c:
return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output); return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output);
case 0x13:
return WrapFixed(this, &nvhost_ctrl_gpu::GetTpcMasks2, input, output);
default: default:
break; break;
} }
@ -261,6 +264,24 @@ NvResult nvhost_ctrl_gpu::GetGpuTime(IoctlGetGpuTime& params) {
return NvResult::Success; return NvResult::Success;
} }
NvResult nvhost_ctrl_gpu::GetTpcMasks2(IoctlGetTpcMasks& params) {
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size={}", params.mask_buf_size);
// Validate input parameters
if (params.mask_buf_size == 0 || params.mask_buf_size > params.tpc_mask_buf.size()) {
LOG_ERROR(Service_NVDRV, "Invalid mask buffer size {}", params.mask_buf_size);
return NvResult::InvalidValue;
}
// Set up TPC mask values based on GPU configuration
// Using conservative values for compatibility
params.mask_buf_size = 1;
params.tpc_mask_buf[0] = 0x1; // Enable first TPC only
LOG_DEBUG(Service_NVDRV, "TPC mask set to 0x{:x}", params.tpc_mask_buf[0]);
return NvResult::Success;
}
Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) { Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) {
switch (event_id) { switch (event_id) {
case 1: case 1:

View file

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@ -34,6 +35,11 @@ public:
Kernel::KEvent* QueryEvent(u32 event_id) override; Kernel::KEvent* QueryEvent(u32 event_id) override;
struct IoctlGetTpcMasks {
u32 mask_buf_size{};
std::array<u32, 1> tpc_mask_buf{};
};
private: private:
static constexpr std::size_t MaxZBCTableSize = 16; static constexpr std::size_t MaxZBCTableSize = 16;
static constexpr std::size_t MaxZBCFormats = 32; static constexpr std::size_t MaxZBCFormats = 32;
@ -201,6 +207,8 @@ private:
NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params); NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params);
NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask); NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask);
NvResult GetTpcMasks2(IoctlGetTpcMasks& params);
NvResult GetActiveSlotMask(IoctlActiveSlotMask& params); NvResult GetActiveSlotMask(IoctlActiveSlotMask& params);
NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params); NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params);
NvResult ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params); NvResult ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params);