Jelajahi Sumber

Merge pull request #384 from Subv/nvhost-remap

 Nvdrv/nvhost-as-gpu: Implemented the ioctl REMAP command.
bunnei 8 tahun lalu
induk
melakukan
bf25299272

+ 45 - 0
src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp

@@ -27,6 +27,11 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vecto
     case IoctlCommand::IocGetVaRegionsCommand:
     case IoctlCommand::IocGetVaRegionsCommand:
         return GetVARegions(input, output);
         return GetVARegions(input, output);
     }
     }
+
+    if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand)
+        return Remap(input, output);
+
+    UNIMPLEMENTED_MSG("Unimplemented ioctl command");
     return 0;
     return 0;
 }
 }
 
 
@@ -56,6 +61,36 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
     return 0;
     return 0;
 }
 }
 
 
+u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
+    size_t num_entries = input.size() / sizeof(IoctlRemapEntry);
+
+    NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries);
+
+    std::vector<IoctlRemapEntry> entries(num_entries);
+    std::memcpy(entries.data(), input.data(), input.size());
+
+    auto& gpu = Core::System::GetInstance().GPU();
+
+    for (const auto& entry : entries) {
+        NGLOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
+                      entry.offset, entry.nvmap_handle, entry.pages);
+        Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10;
+
+        auto object = nvmap_dev->GetObject(entry.nvmap_handle);
+        ASSERT(object);
+
+        ASSERT(object->status == nvmap::Object::Status::Allocated);
+
+        u64 size = static_cast<u64>(entry.pages) << 0x10;
+        ASSERT(size <= object->size);
+
+        Tegra::GPUVAddr returned = gpu.memory_manager->MapBufferEx(object->addr, offset, size);
+        ASSERT(returned == offset);
+    }
+    std::memcpy(output.data(), entries.data(), output.size());
+    return 0;
+}
+
 u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
 u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
     IoctlMapBufferEx params{};
     IoctlMapBufferEx params{};
     std::memcpy(&params, input.data(), input.size());
     std::memcpy(&params, input.data(), input.size());
@@ -73,6 +108,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
     auto object = nvmap_dev->GetObject(params.nvmap_handle);
     auto object = nvmap_dev->GetObject(params.nvmap_handle);
     ASSERT(object);
     ASSERT(object);
 
 
+    // We can only map objects that have already been assigned a CPU address.
+    ASSERT(object->status == nvmap::Object::Status::Allocated);
+
+    ASSERT(params.buffer_offset == 0);
+
+    // The real nvservices doesn't make a distinction between handles and ids, and
+    // object can only have one handle and it will be the same as its id. Assert that this is the
+    // case to prevent unexpected behavior.
+    ASSERT(object->id == params.nvmap_handle);
+
     auto& gpu = Core::System::GetInstance().GPU();
     auto& gpu = Core::System::GetInstance().GPU();
 
 
     if (params.flags & 1) {
     if (params.flags & 1) {

+ 12 - 0
src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h

@@ -26,6 +26,7 @@ private:
     enum class IoctlCommand : u32_le {
     enum class IoctlCommand : u32_le {
         IocInitalizeExCommand = 0x40284109,
         IocInitalizeExCommand = 0x40284109,
         IocAllocateSpaceCommand = 0xC0184102,
         IocAllocateSpaceCommand = 0xC0184102,
+        IocRemapCommand = 0x00000014,
         IocMapBufferExCommand = 0xC0284106,
         IocMapBufferExCommand = 0xC0284106,
         IocBindChannelCommand = 0x40044101,
         IocBindChannelCommand = 0x40044101,
         IocGetVaRegionsCommand = 0xC0404108,
         IocGetVaRegionsCommand = 0xC0404108,
@@ -54,6 +55,16 @@ private:
     };
     };
     static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
     static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
 
 
+    struct IoctlRemapEntry {
+        u16_le flags;
+        u16_le kind;
+        u32_le nvmap_handle;
+        INSERT_PADDING_WORDS(1);
+        u32_le offset;
+        u32_le pages;
+    };
+    static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
+
     struct IoctlMapBufferEx {
     struct IoctlMapBufferEx {
         u32_le flags; // bit0: fixed_offset, bit2: cacheable
         u32_le flags; // bit0: fixed_offset, bit2: cacheable
         u32_le kind;  // -1 is default
         u32_le kind;  // -1 is default
@@ -91,6 +102,7 @@ private:
 
 
     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 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
     u32 MapBufferEx(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);