Merge pull request #456 from Subv/unmap_buffer
Implemented nvhost-as-gpu's UnmapBuffer and nvmap's Free ioctls.
This commit is contained in:
		@@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,8 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& o
 | 
				
			|||||||
        return IocFromId(input, output);
 | 
					        return IocFromId(input, output);
 | 
				
			||||||
    case IoctlCommand::Param:
 | 
					    case IoctlCommand::Param:
 | 
				
			||||||
        return IocParam(input, output);
 | 
					        return IocParam(input, output);
 | 
				
			||||||
 | 
					    case IoctlCommand::Free:
 | 
				
			||||||
 | 
					        return IocFree(input, output);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    UNIMPLEMENTED_MSG("Unimplemented ioctl");
 | 
					    UNIMPLEMENTED_MSG("Unimplemented ioctl");
 | 
				
			||||||
@@ -45,6 +47,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
 | 
				
			|||||||
    object->id = next_id++;
 | 
					    object->id = next_id++;
 | 
				
			||||||
    object->size = params.size;
 | 
					    object->size = params.size;
 | 
				
			||||||
    object->status = Object::Status::Created;
 | 
					    object->status = Object::Status::Created;
 | 
				
			||||||
 | 
					    object->refcount = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    u32 handle = next_handle++;
 | 
					    u32 handle = next_handle++;
 | 
				
			||||||
    handles[handle] = std::move(object);
 | 
					    handles[handle] = std::move(object);
 | 
				
			||||||
@@ -101,6 +104,8 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
 | 
				
			|||||||
                            [&](const auto& entry) { return entry.second->id == params.id; });
 | 
					                            [&](const auto& entry) { return entry.second->id == params.id; });
 | 
				
			||||||
    ASSERT(itr != handles.end());
 | 
					    ASSERT(itr != handles.end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    itr->second->refcount++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Return the existing handle instead of creating a new one.
 | 
					    // Return the existing handle instead of creating a new one.
 | 
				
			||||||
    params.handle = itr->first;
 | 
					    params.handle = itr->first;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,4 +147,34 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
 | 
				
			||||||
 | 
					    enum FreeFlags {
 | 
				
			||||||
 | 
					        Freed = 0,
 | 
				
			||||||
 | 
					        NotFreedYet = 1,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IocFreeParams params;
 | 
				
			||||||
 | 
					    std::memcpy(¶ms, input.data(), sizeof(params));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NGLOG_WARNING(Service_NVDRV, "(STUBBED) called");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto itr = handles.find(params.handle);
 | 
				
			||||||
 | 
					    ASSERT(itr != handles.end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    itr->second->refcount--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    params.refcount = itr->second->refcount;
 | 
				
			||||||
 | 
					    params.size = itr->second->size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (itr->second->refcount == 0)
 | 
				
			||||||
 | 
					        params.flags = Freed;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        params.flags = NotFreedYet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    handles.erase(params.handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::memcpy(output.data(), ¶ms, sizeof(params));
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Service::Nvidia::Devices
 | 
					} // namespace Service::Nvidia::Devices
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ public:
 | 
				
			|||||||
        u8 kind;
 | 
					        u8 kind;
 | 
				
			||||||
        VAddr addr;
 | 
					        VAddr addr;
 | 
				
			||||||
        Status status;
 | 
					        Status status;
 | 
				
			||||||
 | 
					        u32 refcount;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::shared_ptr<Object> GetObject(u32 handle) const {
 | 
					    std::shared_ptr<Object> GetObject(u32 handle) const {
 | 
				
			||||||
@@ -59,7 +60,8 @@ private:
 | 
				
			|||||||
        FromId = 0xC0080103,
 | 
					        FromId = 0xC0080103,
 | 
				
			||||||
        Alloc = 0xC0200104,
 | 
					        Alloc = 0xC0200104,
 | 
				
			||||||
        Param = 0xC00C0109,
 | 
					        Param = 0xC00C0109,
 | 
				
			||||||
        GetId = 0xC008010E
 | 
					        GetId = 0xC008010E,
 | 
				
			||||||
 | 
					        Free = 0xC0180105,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct IocCreateParams {
 | 
					    struct IocCreateParams {
 | 
				
			||||||
@@ -102,11 +104,21 @@ private:
 | 
				
			|||||||
        u32_le value;
 | 
					        u32_le value;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct IocFreeParams {
 | 
				
			||||||
 | 
					        u32_le handle;
 | 
				
			||||||
 | 
					        INSERT_PADDING_BYTES(4);
 | 
				
			||||||
 | 
					        u64_le refcount;
 | 
				
			||||||
 | 
					        u32_le size;
 | 
				
			||||||
 | 
					        u32_le flags;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
 | 
					    u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
 | 
				
			||||||
    u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
 | 
					    u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
 | 
				
			||||||
    u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
 | 
					    u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
 | 
				
			||||||
    u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
 | 
					    u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
 | 
				
			||||||
    u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
 | 
					    u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
 | 
				
			||||||
 | 
					    u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Service::Nvidia::Devices
 | 
					} // namespace Service::Nvidia::Devices
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user