mirror of
https://github.com/yuzu-mirror/yuzu
synced 2024-12-14 06:02:33 +00:00
GPU: Implemented nvhost-as-gpu's UnmapBuffer ioctl.
It removes a mapping previously created with the MapBufferEx ioctl.
This commit is contained in:
parent
1b5c02fc37
commit
72b5c448cf
4 changed files with 70 additions and 0 deletions
|
@ -26,6 +26,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vecto
|
||||||
return BindChannel(input, output);
|
return BindChannel(input, output);
|
||||||
case IoctlCommand::IocGetVaRegionsCommand:
|
case IoctlCommand::IocGetVaRegionsCommand:
|
||||||
return GetVARegions(input, output);
|
return GetVARegions(input, output);
|
||||||
|
case IoctlCommand::IocUnmapBufferCommand:
|
||||||
|
return UnmapBuffer(input, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand)
|
if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand)
|
||||||
|
@ -125,6 +127,37 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||||
params.offset = gpu.memory_manager->MapBufferEx(object->addr, object->size);
|
params.offset = gpu.memory_manager->MapBufferEx(object->addr, object->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new mapping entry for this operation.
|
||||||
|
ASSERT_MSG(buffer_mappings.find(params.offset) == buffer_mappings.end(),
|
||||||
|
"Offset is already mapped");
|
||||||
|
|
||||||
|
BufferMapping mapping{};
|
||||||
|
mapping.nvmap_handle = params.nvmap_handle;
|
||||||
|
mapping.offset = params.offset;
|
||||||
|
mapping.size = object->size;
|
||||||
|
|
||||||
|
buffer_mappings[params.offset] = mapping;
|
||||||
|
|
||||||
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
|
IoctlUnmapBuffer params{};
|
||||||
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
|
NGLOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
|
||||||
|
|
||||||
|
auto& gpu = Core::System::GetInstance().GPU();
|
||||||
|
|
||||||
|
auto itr = buffer_mappings.find(params.offset);
|
||||||
|
|
||||||
|
ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping");
|
||||||
|
|
||||||
|
params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size);
|
||||||
|
|
||||||
|
buffer_mappings.erase(itr->second.offset);
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -30,6 +31,7 @@ private:
|
||||||
IocMapBufferExCommand = 0xC0284106,
|
IocMapBufferExCommand = 0xC0284106,
|
||||||
IocBindChannelCommand = 0x40044101,
|
IocBindChannelCommand = 0x40044101,
|
||||||
IocGetVaRegionsCommand = 0xC0404108,
|
IocGetVaRegionsCommand = 0xC0404108,
|
||||||
|
IocUnmapBufferCommand = 0xC0084105,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IoctlInitalizeEx {
|
struct IoctlInitalizeEx {
|
||||||
|
@ -76,6 +78,11 @@ private:
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
|
static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
|
||||||
|
|
||||||
|
struct IoctlUnmapBuffer {
|
||||||
|
u64_le offset;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
|
||||||
|
|
||||||
struct IoctlBindChannel {
|
struct IoctlBindChannel {
|
||||||
u32_le fd;
|
u32_le fd;
|
||||||
};
|
};
|
||||||
|
@ -98,12 +105,22 @@ private:
|
||||||
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
|
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
|
||||||
"IoctlGetVaRegions is incorrect size");
|
"IoctlGetVaRegions is incorrect size");
|
||||||
|
|
||||||
|
struct BufferMapping {
|
||||||
|
u64 offset;
|
||||||
|
u64 size;
|
||||||
|
u32 nvmap_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Map containing the nvmap object mappings in GPU memory.
|
||||||
|
std::unordered_map<u64, BufferMapping> buffer_mappings;
|
||||||
|
|
||||||
u32 channel{};
|
u32 channel{};
|
||||||
|
|
||||||
u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
|
u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
|
u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
|
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
|
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,25 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
|
||||||
return gpu_addr;
|
return gpu_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
|
||||||
|
ASSERT((gpu_addr & PAGE_MASK) == 0);
|
||||||
|
|
||||||
|
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
|
||||||
|
ASSERT(PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Allocated) &&
|
||||||
|
PageSlot(gpu_addr + offset) != static_cast<u64>(PageStatus::Unmapped));
|
||||||
|
PageSlot(gpu_addr + offset) = static_cast<u64>(PageStatus::Unmapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the region mappings that are contained within the unmapped region
|
||||||
|
mapped_regions.erase(std::remove_if(mapped_regions.begin(), mapped_regions.end(),
|
||||||
|
[&](const MappedRegion& region) {
|
||||||
|
return region.gpu_addr <= gpu_addr &&
|
||||||
|
region.gpu_addr + region.size < gpu_addr + size;
|
||||||
|
}),
|
||||||
|
mapped_regions.end());
|
||||||
|
return gpu_addr;
|
||||||
|
}
|
||||||
|
|
||||||
boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
|
boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
|
||||||
GPUVAddr gpu_addr = 0;
|
GPUVAddr gpu_addr = 0;
|
||||||
u64 free_space = 0;
|
u64 free_space = 0;
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align);
|
GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align);
|
||||||
GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
|
GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
|
||||||
GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size);
|
GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size);
|
||||||
|
GPUVAddr UnmapBuffer(GPUVAddr gpu_addr, u64 size);
|
||||||
boost::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr);
|
boost::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr);
|
||||||
std::vector<GPUVAddr> CpuToGpuAddress(VAddr cpu_addr) const;
|
std::vector<GPUVAddr> CpuToGpuAddress(VAddr cpu_addr) const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue