From b2608472181e07eccb642c444dbbfadca9dc1bc2 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Mon, 12 Oct 2020 17:36:52 -0700
Subject: [PATCH] hle: service: nvdrv: Implement nvhost_as_gpu::FreeSpace.

- This is used by Super Mario 3D All-Stars.
---
 .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp  | 16 ++++++++++++++++
 .../hle/service/nvdrv/devices/nvhost_as_gpu.h    |  9 +++++++++
 2 files changed, 25 insertions(+)

diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 39bd2a45b..f2529a12e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -46,6 +46,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
         return GetVARegions(input, output);
     case IoctlCommand::IocUnmapBufferCommand:
         return UnmapBuffer(input, output);
+    case IoctlCommand::IocFreeSpaceCommand:
+        return FreeSpace(input, output);
     default:
         break;
     }
@@ -91,6 +93,20 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
     return result;
 }
 
+u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
+    IoctlFreeSpace params{};
+    std::memcpy(&params, input.data(), input.size());
+
+    LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
+              params.pages, params.page_size);
+
+    system.GPU().MemoryManager().Unmap(params.offset,
+                                       static_cast<std::size_t>(params.pages) * params.page_size);
+
+    std::memcpy(output.data(), &params, output.size());
+    return NvErrCodes::Success;
+}
+
 u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
     const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
 
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 9a0cdff0c..fcdb40d93 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -82,6 +82,7 @@ private:
         IocBindChannelCommand = 0x40044101,
         IocGetVaRegionsCommand = 0xC0404108,
         IocUnmapBufferCommand = 0xC0084105,
+        IocFreeSpaceCommand = 0xC0104103,
     };
 
     struct IoctlInitalizeEx {
@@ -107,6 +108,13 @@ private:
     };
     static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
 
+    struct IoctlFreeSpace {
+        u64_le offset;
+        u32_le pages;
+        u32_le page_size;
+    };
+    static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
+
     struct IoctlRemapEntry {
         u16_le flags;
         u16_le kind;
@@ -162,6 +170,7 @@ private:
     u32 Remap(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 FreeSpace(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);