Răsfoiți Sursa

NVDRV: Implement new NvMap

Fernando Sahmkow 4 ani în urmă
părinte
comite
de0e8eff42

+ 65 - 54
src/core/hle/service/nvdrv/core/nvmap.cpp

@@ -17,7 +17,7 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress)
     std::scoped_lock lock(mutex);
     std::scoped_lock lock(mutex);
 
 
     // Handles cannot be allocated twice
     // Handles cannot be allocated twice
-    if (allocated) [[unlikely]]
+    if (allocated)
         return NvResult::AccessDenied;
         return NvResult::AccessDenied;
 
 
     flags = pFlags;
     flags = pFlags;
@@ -61,33 +61,34 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) {
 
 
 NvMap::NvMap() = default;
 NvMap::NvMap() = default;
 
 
-void NvMap::AddHandle(std::shared_ptr<Handle> handleDesc) {
+void NvMap::AddHandle(std::shared_ptr<Handle> handle_description) {
     std::scoped_lock lock(handles_lock);
     std::scoped_lock lock(handles_lock);
 
 
-    handles.emplace(handleDesc->id, std::move(handleDesc));
+    handles.emplace(handle_description->id, std::move(handle_description));
 }
 }
 
 
-void NvMap::UnmapHandle(Handle& handleDesc) {
+void NvMap::UnmapHandle(Handle& handle_description) {
     // Remove pending unmap queue entry if needed
     // Remove pending unmap queue entry if needed
-    if (handleDesc.unmap_queue_entry) {
-        unmap_queue.erase(*handleDesc.unmap_queue_entry);
-        handleDesc.unmap_queue_entry.reset();
+    if (handle_description.unmap_queue_entry) {
+        unmap_queue.erase(*handle_description.unmap_queue_entry);
+        handle_description.unmap_queue_entry.reset();
     }
     }
 
 
     // Free and unmap the handle from the SMMU
     // Free and unmap the handle from the SMMU
     /*
     /*
-    state.soc->smmu.Unmap(handleDesc.pin_virt_address, static_cast<u32>(handleDesc.aligned_size));
-    smmuAllocator.Free(handleDesc.pin_virt_address, static_cast<u32>(handleDesc.aligned_size));
-    handleDesc.pin_virt_address = 0;
+    state.soc->smmu.Unmap(handle_description.pin_virt_address,
+    static_cast<u32>(handle_description.aligned_size));
+    smmuAllocator.Free(handle_description.pin_virt_address,
+    static_cast<u32>(handle_description.aligned_size)); handle_description.pin_virt_address = 0;
     */
     */
 }
 }
 
 
-bool NvMap::TryRemoveHandle(const Handle& handleDesc) {
+bool NvMap::TryRemoveHandle(const Handle& handle_description) {
     // No dupes left, we can remove from handle map
     // No dupes left, we can remove from handle map
-    if (handleDesc.dupes == 0 && handleDesc.internal_dupes == 0) {
+    if (handle_description.dupes == 0 && handle_description.internal_dupes == 0) {
         std::scoped_lock lock(handles_lock);
         std::scoped_lock lock(handles_lock);
 
 
-        auto it{handles.find(handleDesc.id)};
+        auto it{handles.find(handle_description.id)};
         if (it != handles.end())
         if (it != handles.end())
             handles.erase(it);
             handles.erase(it);
 
 
@@ -102,10 +103,10 @@ NvResult NvMap::CreateHandle(u64 size, std::shared_ptr<NvMap::Handle>& result_ou
         return NvResult::BadValue;
         return NvResult::BadValue;
 
 
     u32 id{next_handle_id.fetch_add(HandleIdIncrement, std::memory_order_relaxed)};
     u32 id{next_handle_id.fetch_add(HandleIdIncrement, std::memory_order_relaxed)};
-    auto handleDesc{std::make_shared<Handle>(size, id)};
-    AddHandle(handleDesc);
+    auto handle_description{std::make_shared<Handle>(size, id)};
+    AddHandle(handle_description);
 
 
-    result_out = handleDesc;
+    result_out = handle_description;
     return NvResult::Success;
     return NvResult::Success;
 }
 }
 
 
@@ -118,73 +119,83 @@ std::shared_ptr<NvMap::Handle> NvMap::GetHandle(Handle::Id handle) {
     }
     }
 }
 }
 
 
+VAddr NvMap::GetHandleAddress(Handle::Id handle) {
+    std::scoped_lock lock(handles_lock);
+    try {
+        return handles.at(handle)->address;
+    } catch ([[maybe_unused]] std::out_of_range& e) {
+        return 0;
+    }
+}
+
 u32 NvMap::PinHandle(NvMap::Handle::Id handle) {
 u32 NvMap::PinHandle(NvMap::Handle::Id handle) {
     UNIMPLEMENTED_MSG("pinning");
     UNIMPLEMENTED_MSG("pinning");
     return 0;
     return 0;
     /*
     /*
-    auto handleDesc{GetHandle(handle)};
-    if (!handleDesc)
+    auto handle_description{GetHandle(handle)};
+    if (!handle_description)
         [[unlikely]] return 0;
         [[unlikely]] return 0;
 
 
-    std::scoped_lock lock(handleDesc->mutex);
-    if (!handleDesc->pins) {
+    std::scoped_lock lock(handle_description->mutex);
+    if (!handle_description->pins) {
         // If we're in the unmap queue we can just remove ourselves and return since we're already
         // If we're in the unmap queue we can just remove ourselves and return since we're already
         // mapped
         // mapped
         {
         {
             // Lock now to prevent our queue entry from being removed for allocation in-between the
             // Lock now to prevent our queue entry from being removed for allocation in-between the
             // following check and erase
             // following check and erase
             std::scoped_lock queueLock(unmap_queue_lock);
             std::scoped_lock queueLock(unmap_queue_lock);
-            if (handleDesc->unmap_queue_entry) {
-                unmap_queue.erase(*handleDesc->unmap_queue_entry);
-                handleDesc->unmap_queue_entry.reset();
+            if (handle_description->unmap_queue_entry) {
+                unmap_queue.erase(*handle_description->unmap_queue_entry);
+                handle_description->unmap_queue_entry.reset();
 
 
-                handleDesc->pins++;
-                return handleDesc->pin_virt_address;
+                handle_description->pins++;
+                return handle_description->pin_virt_address;
             }
             }
         }
         }
 
 
         // If not then allocate some space and map it
         // If not then allocate some space and map it
         u32 address{};
         u32 address{};
-        while (!(address = smmuAllocator.Allocate(static_cast<u32>(handleDesc->aligned_size)))) {
+        while (!(address =
+    smmuAllocator.Allocate(static_cast<u32>(handle_description->aligned_size)))) {
             // Free handles until the allocation succeeds
             // Free handles until the allocation succeeds
             std::scoped_lock queueLock(unmap_queue_lock);
             std::scoped_lock queueLock(unmap_queue_lock);
             if (auto freeHandleDesc{unmap_queue.front()}) {
             if (auto freeHandleDesc{unmap_queue.front()}) {
                 // Handles in the unmap queue are guaranteed not to be pinned so don't bother
                 // Handles in the unmap queue are guaranteed not to be pinned so don't bother
                 // checking if they are before unmapping
                 // checking if they are before unmapping
                 std::scoped_lock freeLock(freeHandleDesc->mutex);
                 std::scoped_lock freeLock(freeHandleDesc->mutex);
-                if (handleDesc->pin_virt_address)
+                if (handle_description->pin_virt_address)
                     UnmapHandle(*freeHandleDesc);
                     UnmapHandle(*freeHandleDesc);
             } else {
             } else {
                 LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!");
                 LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!");
             }
             }
         }
         }
 
 
-        state.soc->smmu.Map(address, handleDesc->GetPointer(),
-                            static_cast<u32>(handleDesc->aligned_size));
-        handleDesc->pin_virt_address = address;
+        state.soc->smmu.Map(address, handle_description->GetPointer(),
+                            static_cast<u32>(handle_description->aligned_size));
+        handle_description->pin_virt_address = address;
     }
     }
 
 
-    handleDesc->pins++;
-    return handleDesc->pin_virt_address;
+    handle_description->pins++;
+    return handle_description->pin_virt_address;
     */
     */
 }
 }
 
 
 void NvMap::UnpinHandle(Handle::Id handle) {
 void NvMap::UnpinHandle(Handle::Id handle) {
     UNIMPLEMENTED_MSG("Unpinning");
     UNIMPLEMENTED_MSG("Unpinning");
     /*
     /*
-    auto handleDesc{GetHandle(handle)};
-    if (!handleDesc)
+    auto handle_description{GetHandle(handle)};
+    if (!handle_description)
         return;
         return;
 
 
-    std::scoped_lock lock(handleDesc->mutex);
-    if (--handleDesc->pins < 0) {
+    std::scoped_lock lock(handle_description->mutex);
+    if (--handle_description->pins < 0) {
         LOG_WARNING(Service_NVDRV, "Pin count imbalance detected!");
         LOG_WARNING(Service_NVDRV, "Pin count imbalance detected!");
-    } else if (!handleDesc->pins) {
+    } else if (!handle_description->pins) {
         std::scoped_lock queueLock(unmap_queue_lock);
         std::scoped_lock queueLock(unmap_queue_lock);
 
 
         // Add to the unmap queue allowing this handle's memory to be freed if needed
         // Add to the unmap queue allowing this handle's memory to be freed if needed
-        unmap_queue.push_back(handleDesc);
-        handleDesc->unmap_queue_entry = std::prev(unmap_queue.end());
+        unmap_queue.push_back(handle_description);
+        handle_description->unmap_queue_entry = std::prev(unmap_queue.end());
     }
     }
     */
     */
 }
 }
@@ -195,39 +206,39 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna
 
 
     // We use a weak ptr here so we can tell when the handle has been freed and report that back to
     // We use a weak ptr here so we can tell when the handle has been freed and report that back to
     // guest
     // guest
-    if (auto handleDesc = hWeak.lock()) {
-        std::scoped_lock lock(handleDesc->mutex);
+    if (auto handle_description = hWeak.lock()) {
+        std::scoped_lock lock(handle_description->mutex);
 
 
         if (internal_session) {
         if (internal_session) {
-            if (--handleDesc->internal_dupes < 0)
+            if (--handle_description->internal_dupes < 0)
                 LOG_WARNING(Service_NVDRV, "Internal duplicate count imbalance detected!");
                 LOG_WARNING(Service_NVDRV, "Internal duplicate count imbalance detected!");
         } else {
         } else {
-            if (--handleDesc->dupes < 0) {
+            if (--handle_description->dupes < 0) {
                 LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!");
                 LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!");
-            } else if (handleDesc->dupes == 0) {
+            } else if (handle_description->dupes == 0) {
                 // Force unmap the handle
                 // Force unmap the handle
-                if (handleDesc->pin_virt_address) {
+                if (handle_description->pin_virt_address) {
                     std::scoped_lock queueLock(unmap_queue_lock);
                     std::scoped_lock queueLock(unmap_queue_lock);
-                    UnmapHandle(*handleDesc);
+                    UnmapHandle(*handle_description);
                 }
                 }
 
 
-                handleDesc->pins = 0;
+                handle_description->pins = 0;
             }
             }
         }
         }
 
 
         // Try to remove the shared ptr to the handle from the map, if nothing else is using the
         // Try to remove the shared ptr to the handle from the map, if nothing else is using the
-        // handle then it will now be freed when `handleDesc` goes out of scope
-        if (TryRemoveHandle(*handleDesc))
-            LOG_ERROR(Service_NVDRV, "Removed nvmap handle: {}", handle);
+        // handle then it will now be freed when `handle_description` goes out of scope
+        if (TryRemoveHandle(*handle_description))
+            LOG_DEBUG(Service_NVDRV, "Removed nvmap handle: {}", handle);
         else
         else
-            LOG_ERROR(Service_NVDRV,
+            LOG_DEBUG(Service_NVDRV,
                       "Tried to free nvmap handle: {} but didn't as it still has duplicates",
                       "Tried to free nvmap handle: {} but didn't as it still has duplicates",
                       handle);
                       handle);
 
 
         freeInfo = {
         freeInfo = {
-            .address = handleDesc->address,
-            .size = handleDesc->size,
-            .was_uncached = handleDesc->flags.map_uncached.Value() != 0,
+            .address = handle_description->address,
+            .size = handle_description->size,
+            .was_uncached = handle_description->flags.map_uncached.Value() != 0,
         };
         };
     } else {
     } else {
         return std::nullopt;
         return std::nullopt;

+ 8 - 4
src/core/hle/service/nvdrv/core/nvmap.h

@@ -59,6 +59,8 @@ public:
         u8 kind{};        //!< Used for memory compression
         u8 kind{};        //!< Used for memory compression
         bool allocated{}; //!< If the handle has been allocated with `Alloc`
         bool allocated{}; //!< If the handle has been allocated with `Alloc`
 
 
+        u64 dma_map_addr{}; //! remove me after implementing pinning.
+
         Handle(u64 size, Id id);
         Handle(u64 size, Id id);
 
 
         /**
         /**
@@ -101,16 +103,16 @@ private:
 
 
     /**
     /**
      * @brief Unmaps and frees the SMMU memory region a handle is mapped to
      * @brief Unmaps and frees the SMMU memory region a handle is mapped to
-     * @note Both `unmap_queue_lock` and `handleDesc.mutex` MUST be locked when calling this
+     * @note Both `unmap_queue_lock` and `handle_description.mutex` MUST be locked when calling this
      */
      */
-    void UnmapHandle(Handle& handleDesc);
+    void UnmapHandle(Handle& handle_description);
 
 
     /**
     /**
      * @brief Removes a handle from the map taking its dupes into account
      * @brief Removes a handle from the map taking its dupes into account
-     * @note handleDesc.mutex MUST be locked when calling this
+     * @note handle_description.mutex MUST be locked when calling this
      * @return If the handle was removed from the map
      * @return If the handle was removed from the map
      */
      */
-    bool TryRemoveHandle(const Handle& handleDesc);
+    bool TryRemoveHandle(const Handle& handle_description);
 
 
 public:
 public:
     /**
     /**
@@ -131,6 +133,8 @@ public:
 
 
     std::shared_ptr<Handle> GetHandle(Handle::Id handle);
     std::shared_ptr<Handle> GetHandle(Handle::Id handle);
 
 
+    VAddr GetHandleAddress(Handle::Id handle);
+
     /**
     /**
      * @brief Maps a handle into the SMMU address space
      * @brief Maps a handle into the SMMU address space
      * @note This operation is refcounted, the number of calls to this must eventually match the
      * @note This operation is refcounted, the number of calls to this must eventually match the

+ 10 - 4
src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp

@@ -5,15 +5,16 @@
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/core_timing.h"
+#include "core/hle/service/nvdrv/core/container.h"
+#include "core/hle/service/nvdrv/core/nvmap.h"
 #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
 #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
-#include "core/hle/service/nvdrv/devices/nvmap.h"
 #include "core/perf_stats.h"
 #include "core/perf_stats.h"
 #include "video_core/gpu.h"
 #include "video_core/gpu.h"
 
 
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 
 
-nvdisp_disp0::nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_)
-    : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {}
+nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
+    : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
 nvdisp_disp0::~nvdisp_disp0() = default;
 nvdisp_disp0::~nvdisp_disp0() = default;
 
 
 NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
 NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -40,7 +41,7 @@ void nvdisp_disp0::OnClose(DeviceFD fd) {}
 void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
 void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
                         u32 height, u32 stride, android::BufferTransformFlags transform,
                         u32 height, u32 stride, android::BufferTransformFlags transform,
                         const Common::Rectangle<int>& crop_rect) {
                         const Common::Rectangle<int>& crop_rect) {
-    const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
+    const VAddr addr = nvmap.GetHandleAddress(buffer_handle);
     LOG_TRACE(Service,
     LOG_TRACE(Service,
               "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
               "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
               addr, offset, width, height, stride, format);
               addr, offset, width, height, stride, format);
@@ -54,4 +55,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form
     system.GetPerfStats().BeginSystemFrame();
     system.GetPerfStats().BeginSystemFrame();
 }
 }
 
 
+Kernel::KEvent* nvdisp_disp0::QueryEvent(u32 event_id) {
+    LOG_CRITICAL(Service_NVDRV, "Unknown DISP Event {}", event_id);
+    return nullptr;
+}
+
 } // namespace Service::Nvidia::Devices
 } // namespace Service::Nvidia::Devices

+ 10 - 2
src/core/hle/service/nvdrv/devices/nvdisp_disp0.h

@@ -11,13 +11,18 @@
 #include "core/hle/service/nvflinger/buffer_transform_flags.h"
 #include "core/hle/service/nvflinger/buffer_transform_flags.h"
 #include "core/hle/service/nvflinger/pixel_format.h"
 #include "core/hle/service/nvflinger/pixel_format.h"
 
 
+namespace Service::Nvidia::NvCore {
+class Container;
+class NvMap;
+} // namespace Service::Nvidia::NvCore
+
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 
 
 class nvmap;
 class nvmap;
 
 
 class nvdisp_disp0 final : public nvdevice {
 class nvdisp_disp0 final : public nvdevice {
 public:
 public:
-    explicit nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_);
+    explicit nvdisp_disp0(Core::System& system_, NvCore::Container& core);
     ~nvdisp_disp0() override;
     ~nvdisp_disp0() override;
 
 
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -35,8 +40,11 @@ public:
               u32 stride, android::BufferTransformFlags transform,
               u32 stride, android::BufferTransformFlags transform,
               const Common::Rectangle<int>& crop_rect);
               const Common::Rectangle<int>& crop_rect);
 
 
+    Kernel::KEvent* QueryEvent(u32 event_id) override;
+
 private:
 private:
-    std::shared_ptr<nvmap> nvmap_dev;
+    NvCore::Container& container;
+    NvCore::NvMap& nvmap;
 };
 };
 
 
 } // namespace Service::Nvidia::Devices
 } // namespace Service::Nvidia::Devices

+ 29 - 25
src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp

@@ -7,15 +7,16 @@
 #include "common/assert.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/core.h"
+#include "core/hle/service/nvdrv/core/container.h"
+#include "core/hle/service/nvdrv/core/nvmap.h"
 #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
 #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
-#include "core/hle/service/nvdrv/devices/nvmap.h"
 #include "video_core/memory_manager.h"
 #include "video_core/memory_manager.h"
 #include "video_core/rasterizer_interface.h"
 #include "video_core/rasterizer_interface.h"
 
 
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 
 
-nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_)
-    : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {}
+nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, NvCore::Container& core)
+    : nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
 nvhost_as_gpu::~nvhost_as_gpu() = default;
 nvhost_as_gpu::~nvhost_as_gpu() = default;
 
 
 NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
 NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -143,7 +144,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& out
         LOG_DEBUG(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
         LOG_DEBUG(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
                   entry.offset, entry.nvmap_handle, entry.pages);
                   entry.offset, entry.nvmap_handle, entry.pages);
 
 
-        const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
+        const auto object{nvmap.GetHandle(entry.nvmap_handle)};
         if (!object) {
         if (!object) {
             LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
             LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
             result = NvResult::InvalidState;
             result = NvResult::InvalidState;
@@ -153,7 +154,8 @@ NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& out
         const auto offset{static_cast<GPUVAddr>(entry.offset) << 0x10};
         const auto offset{static_cast<GPUVAddr>(entry.offset) << 0x10};
         const auto size{static_cast<u64>(entry.pages) << 0x10};
         const auto size{static_cast<u64>(entry.pages) << 0x10};
         const auto map_offset{static_cast<u64>(entry.map_offset) << 0x10};
         const auto map_offset{static_cast<u64>(entry.map_offset) << 0x10};
-        const auto addr{system.GPU().MemoryManager().Map(object->addr + map_offset, offset, size)};
+        const auto addr{
+            system.GPU().MemoryManager().Map(object->address + map_offset, offset, size)};
 
 
         if (!addr) {
         if (!addr) {
             LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
             LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
@@ -176,24 +178,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8
               params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
               params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
               params.offset);
               params.offset);
 
 
-    const auto object{nvmap_dev->GetObject(params.nvmap_handle)};
-    if (!object) {
-        LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
-        std::memcpy(output.data(), &params, output.size());
-        return NvResult::InvalidState;
-    }
-
-    // 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 = system.GPU();
     auto& gpu = system.GPU();
-
-    u64 page_size{params.page_size};
-    if (!page_size) {
-        page_size = object->align;
-    }
-
     if ((params.flags & AddressSpaceFlags::Remap) != AddressSpaceFlags::None) {
     if ((params.flags & AddressSpaceFlags::Remap) != AddressSpaceFlags::None) {
         if (const auto buffer_map{FindBufferMap(params.offset)}; buffer_map) {
         if (const auto buffer_map{FindBufferMap(params.offset)}; buffer_map) {
             const auto cpu_addr{static_cast<VAddr>(buffer_map->CpuAddr() + params.buffer_offset)};
             const auto cpu_addr{static_cast<VAddr>(buffer_map->CpuAddr() + params.buffer_offset)};
@@ -220,10 +205,24 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8
         }
         }
     }
     }
 
 
-    // We can only map objects that have already been assigned a CPU address.
-    ASSERT(object->status == nvmap::Object::Status::Allocated);
+    const auto object{nvmap.GetHandle(params.nvmap_handle)};
+    if (!object) {
+        LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
+        std::memcpy(output.data(), &params, output.size());
+        return NvResult::InvalidState;
+    }
+
+    // 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);
+
+    u64 page_size{params.page_size};
+    if (!page_size) {
+        page_size = object->align;
+    }
 
 
-    const auto physical_address{object->addr + params.buffer_offset};
+    const auto physical_address{object->address + params.buffer_offset};
     u64 size{params.mapping_size};
     u64 size{params.mapping_size};
     if (!size) {
     if (!size) {
         size = object->size;
         size = object->size;
@@ -363,4 +362,9 @@ std::optional<std::size_t> nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) {
     return std::nullopt;
     return std::nullopt;
 }
 }
 
 
+Kernel::KEvent* nvhost_as_gpu::QueryEvent(u32 event_id) {
+    LOG_CRITICAL(Service_NVDRV, "Unknown AS GPU Event {}", event_id);
+    return nullptr;
+}
+
 } // namespace Service::Nvidia::Devices
 } // namespace Service::Nvidia::Devices

+ 10 - 2
src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h

@@ -13,6 +13,11 @@
 #include "common/swap.h"
 #include "common/swap.h"
 #include "core/hle/service/nvdrv/devices/nvdevice.h"
 #include "core/hle/service/nvdrv/devices/nvdevice.h"
 
 
+namespace Service::Nvidia::NvCore {
+class Container;
+class NvMap;
+} // namespace Service::Nvidia::NvCore
+
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 
 
 constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16;
 constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16;
@@ -29,7 +34,7 @@ DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags);
 
 
 class nvhost_as_gpu final : public nvdevice {
 class nvhost_as_gpu final : public nvdevice {
 public:
 public:
-    explicit nvhost_as_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_);
+    explicit nvhost_as_gpu(Core::System& system_, NvCore::Container& core);
     ~nvhost_as_gpu() override;
     ~nvhost_as_gpu() override;
 
 
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -42,6 +47,8 @@ public:
     void OnOpen(DeviceFD fd) override;
     void OnOpen(DeviceFD fd) override;
     void OnClose(DeviceFD fd) override;
     void OnClose(DeviceFD fd) override;
 
 
+    Kernel::KEvent* QueryEvent(u32 event_id) override;
+
 private:
 private:
     class BufferMap final {
     class BufferMap final {
     public:
     public:
@@ -180,7 +187,8 @@ private:
     void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
     void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
     std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
     std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
 
 
-    std::shared_ptr<nvmap> nvmap_dev;
+    NvCore::Container& container;
+    NvCore::NvMap& nvmap;
 
 
     // This is expected to be ordered, therefore we must use a map, not unordered_map
     // This is expected to be ordered, therefore we must use a map, not unordered_map
     std::map<GPUVAddr, BufferMap> buffer_mappings;
     std::map<GPUVAddr, BufferMap> buffer_mappings;

+ 2 - 0
src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp

@@ -279,6 +279,8 @@ Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) {
         ASSERT(events_interface.events[slot]);
         ASSERT(events_interface.events[slot]);
         return events_interface.events[slot];
         return events_interface.events[slot];
     }
     }
+    // Is this possible in hardware?
+    ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id);
     return nullptr;
     return nullptr;
 }
 }
 
 

+ 5 - 4
src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp

@@ -6,6 +6,7 @@
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/service/nvdrv/core/container.h"
 #include "core/hle/service/nvdrv/core/container.h"
+#include "core/hle/service/nvdrv/core/nvmap.h"
 #include "core/hle/service/nvdrv/core/syncpoint_manager.h"
 #include "core/hle/service/nvdrv/core/syncpoint_manager.h"
 #include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
 #include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
 #include "core/hle/service/nvdrv/nvdrv.h"
 #include "core/hle/service/nvdrv/nvdrv.h"
@@ -22,10 +23,10 @@ Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoi
 }
 }
 } // namespace
 } // namespace
 
 
-nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                       EventInterface& events_interface_, NvCore::Container& core_)
-    : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, events_interface{events_interface_},
-      core{core_}, syncpoint_manager{core_.GetSyncpointManager()} {
+nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_,
+                       NvCore::Container& core_)
+    : nvdevice{system_}, events_interface{events_interface_}, core{core_},
+      syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {
     channel_fence.id = syncpoint_manager.AllocateSyncpoint();
     channel_fence.id = syncpoint_manager.AllocateSyncpoint();
     channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id);
     channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id);
     sm_exception_breakpoint_int_report_event =
     sm_exception_breakpoint_int_report_event =

+ 4 - 3
src/core/hle/service/nvdrv/devices/nvhost_gpu.h

@@ -17,6 +17,7 @@ namespace Service::Nvidia {
 
 
 namespace NvCore {
 namespace NvCore {
 class Container;
 class Container;
+class NvMap;
 class SyncpointManager;
 class SyncpointManager;
 } // namespace NvCore
 } // namespace NvCore
 
 
@@ -28,8 +29,8 @@ namespace Service::Nvidia::Devices {
 class nvmap;
 class nvmap;
 class nvhost_gpu final : public nvdevice {
 class nvhost_gpu final : public nvdevice {
 public:
 public:
-    explicit nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                        EventInterface& events_interface_, NvCore::Container& core);
+    explicit nvhost_gpu(Core::System& system_, EventInterface& events_interface_,
+                        NvCore::Container& core);
     ~nvhost_gpu() override;
     ~nvhost_gpu() override;
 
 
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -199,10 +200,10 @@ private:
     NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
 
 
-    std::shared_ptr<nvmap> nvmap_dev;
     EventInterface& events_interface;
     EventInterface& events_interface;
     NvCore::Container& core;
     NvCore::Container& core;
     NvCore::SyncpointManager& syncpoint_manager;
     NvCore::SyncpointManager& syncpoint_manager;
+    NvCore::NvMap& nvmap;
     NvFence channel_fence;
     NvFence channel_fence;
 
 
     // Events
     // Events

+ 2 - 3
src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp

@@ -10,9 +10,8 @@
 
 
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 
 
-nvhost_nvdec::nvhost_nvdec(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                           NvCore::Container& core)
-    : nvhost_nvdec_common{system_, std::move(nvmap_dev_), core} {}
+nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core)
+    : nvhost_nvdec_common{system_, core} {}
 nvhost_nvdec::~nvhost_nvdec() = default;
 nvhost_nvdec::~nvhost_nvdec() = default;
 
 
 NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
 NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,

+ 1 - 2
src/core/hle/service/nvdrv/devices/nvhost_nvdec.h

@@ -10,8 +10,7 @@ namespace Service::Nvidia::Devices {
 
 
 class nvhost_nvdec final : public nvhost_nvdec_common {
 class nvhost_nvdec final : public nvhost_nvdec_common {
 public:
 public:
-    explicit nvhost_nvdec(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                          NvCore::Container& core);
+    explicit nvhost_nvdec(Core::System& system_, NvCore::Container& core);
     ~nvhost_nvdec() override;
     ~nvhost_nvdec() override;
 
 
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,

+ 16 - 10
src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp

@@ -9,9 +9,9 @@
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/service/nvdrv/core/container.h"
 #include "core/hle/service/nvdrv/core/container.h"
+#include "core/hle/service/nvdrv/core/nvmap.h"
 #include "core/hle/service/nvdrv/core/syncpoint_manager.h"
 #include "core/hle/service/nvdrv/core/syncpoint_manager.h"
 #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
 #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
-#include "core/hle/service/nvdrv/devices/nvmap.h"
 #include "core/memory.h"
 #include "core/memory.h"
 #include "video_core/memory_manager.h"
 #include "video_core/memory_manager.h"
 #include "video_core/renderer_base.h"
 #include "video_core/renderer_base.h"
@@ -45,10 +45,9 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s
 }
 }
 } // Anonymous namespace
 } // Anonymous namespace
 
 
-nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                                         NvCore::Container& core_)
-    : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, core{core_},
-      syncpoint_manager{core.GetSyncpointManager()} {}
+nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_)
+    : nvdevice{system_}, core{core_},
+      syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {}
 nvhost_nvdec_common::~nvhost_nvdec_common() = default;
 nvhost_nvdec_common::~nvhost_nvdec_common() = default;
 
 
 NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
 NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
@@ -90,10 +89,10 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
         }
         }
     }
     }
     for (const auto& cmd_buffer : command_buffers) {
     for (const auto& cmd_buffer : command_buffers) {
-        const auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
+        const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
         ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
         ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
         Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
         Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
-        system.Memory().ReadBlock(object->addr + cmd_buffer.offset, cmdlist.data(),
+        system.Memory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
                                   cmdlist.size() * sizeof(u32));
                                   cmdlist.size() * sizeof(u32));
         gpu.PushCommandBuffer(fd_to_id[fd], cmdlist);
         gpu.PushCommandBuffer(fd_to_id[fd], cmdlist);
     }
     }
@@ -125,6 +124,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::ve
 
 
 NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
 NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
     IoctlGetWaitbase params{};
     IoctlGetWaitbase params{};
+    LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
     std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
     std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
     params.value = 0; // Seems to be hard coded at 0
     params.value = 0; // Seems to be hard coded at 0
     std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
     std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
@@ -141,7 +141,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
     auto& gpu = system.GPU();
     auto& gpu = system.GPU();
 
 
     for (auto& cmd_buffer : cmd_buffer_handles) {
     for (auto& cmd_buffer : cmd_buffer_handles) {
-        auto object{nvmap_dev->GetObject(cmd_buffer.map_handle)};
+        auto object{nvmap.GetHandle(cmd_buffer.map_handle)};
         if (!object) {
         if (!object) {
             LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle);
             LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle);
             std::memcpy(output.data(), &params, output.size());
             std::memcpy(output.data(), &params, output.size());
@@ -150,7 +150,8 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
         if (object->dma_map_addr == 0) {
         if (object->dma_map_addr == 0) {
             // NVDEC and VIC memory is in the 32-bit address space
             // NVDEC and VIC memory is in the 32-bit address space
             // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space
             // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space
-            const GPUVAddr low_addr = gpu.MemoryManager().MapAllocate32(object->addr, object->size);
+            const GPUVAddr low_addr =
+                gpu.MemoryManager().MapAllocate32(object->address, object->size);
             object->dma_map_addr = static_cast<u32>(low_addr);
             object->dma_map_addr = static_cast<u32>(low_addr);
             // Ensure that the dma_map_addr is indeed in the lower 32-bit address space.
             // Ensure that the dma_map_addr is indeed in the lower 32-bit address space.
             ASSERT(object->dma_map_addr == low_addr);
             ASSERT(object->dma_map_addr == low_addr);
@@ -158,7 +159,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
         if (!object->dma_map_addr) {
         if (!object->dma_map_addr) {
             LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
             LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
         } else {
         } else {
-            cmd_buffer.map_address = object->dma_map_addr;
+            cmd_buffer.map_address = static_cast<u32_le>(object->dma_map_addr);
         }
         }
     }
     }
     std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
     std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
@@ -184,4 +185,9 @@ NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
     return NvResult::Success;
     return NvResult::Success;
 }
 }
 
 
+Kernel::KEvent* nvhost_nvdec_common::QueryEvent(u32 event_id) {
+    LOG_CRITICAL(Service_NVDRV, "Unknown HOSTX1 Event {}", event_id);
+    return nullptr;
+}
+
 } // namespace Service::Nvidia::Devices
 } // namespace Service::Nvidia::Devices

+ 6 - 5
src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h

@@ -11,17 +11,16 @@
 namespace Service::Nvidia {
 namespace Service::Nvidia {
 
 
 namespace NvCore {
 namespace NvCore {
-class SyncpointManager;
 class Container;
 class Container;
+class NvMap;
+class SyncpointManager;
 } // namespace NvCore
 } // namespace NvCore
 
 
 namespace Devices {
 namespace Devices {
-class nvmap;
 
 
 class nvhost_nvdec_common : public nvdevice {
 class nvhost_nvdec_common : public nvdevice {
 public:
 public:
-    explicit nvhost_nvdec_common(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                                 NvCore::Container& core);
+    explicit nvhost_nvdec_common(Core::System& system_, NvCore::Container& core);
     ~nvhost_nvdec_common() override;
     ~nvhost_nvdec_common() override;
 
 
 protected:
 protected:
@@ -114,12 +113,14 @@ protected:
     NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
 
 
+    Kernel::KEvent* QueryEvent(u32 event_id) override;
+
     std::unordered_map<DeviceFD, u32> fd_to_id{};
     std::unordered_map<DeviceFD, u32> fd_to_id{};
     s32_le nvmap_fd{};
     s32_le nvmap_fd{};
     u32_le submit_timeout{};
     u32_le submit_timeout{};
-    std::shared_ptr<nvmap> nvmap_dev;
     NvCore::Container& core;
     NvCore::Container& core;
     NvCore::SyncpointManager& syncpoint_manager;
     NvCore::SyncpointManager& syncpoint_manager;
+    NvCore::NvMap& nvmap;
     std::array<u32, MaxSyncPoints> device_syncpoints{};
     std::array<u32, MaxSyncPoints> device_syncpoints{};
 };
 };
 }; // namespace Devices
 }; // namespace Devices

+ 2 - 3
src/core/hle/service/nvdrv/devices/nvhost_vic.cpp

@@ -8,9 +8,8 @@
 #include "video_core/renderer_base.h"
 #include "video_core/renderer_base.h"
 
 
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
-nvhost_vic::nvhost_vic(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                       NvCore::Container& core)
-    : nvhost_nvdec_common{system_, std::move(nvmap_dev_), core} {}
+nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core)
+    : nvhost_nvdec_common{system_, core} {}
 
 
 nvhost_vic::~nvhost_vic() = default;
 nvhost_vic::~nvhost_vic() = default;
 
 

+ 1 - 2
src/core/hle/service/nvdrv/devices/nvhost_vic.h

@@ -9,8 +9,7 @@ namespace Service::Nvidia::Devices {
 
 
 class nvhost_vic final : public nvhost_nvdec_common {
 class nvhost_vic final : public nvhost_nvdec_common {
 public:
 public:
-    explicit nvhost_vic(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
-                        NvCore::Container& core);
+    explicit nvhost_vic(Core::System& system_, NvCore::Container& core);
     ~nvhost_vic();
     ~nvhost_vic();
 
 
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,

+ 105 - 115
src/core/hle/service/nvdrv/devices/nvmap.cpp

@@ -2,19 +2,24 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 
 #include <algorithm>
 #include <algorithm>
+#include <bit>
 #include <cstring>
 #include <cstring>
 
 
+#include "common/alignment.h"
 #include "common/assert.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/service/nvdrv/core/container.h"
+#include "core/hle/service/nvdrv/core/nvmap.h"
 #include "core/hle/service/nvdrv/devices/nvmap.h"
 #include "core/hle/service/nvdrv/devices/nvmap.h"
+#include "core/memory.h"
+
+using Core::Memory::YUZU_PAGESIZE;
 
 
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 
 
-nvmap::nvmap(Core::System& system_) : nvdevice{system_} {
-    // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
-    // represent this.
-    CreateObject(0);
-}
+nvmap::nvmap(Core::System& system_, NvCore::Container& container_)
+    : nvdevice{system_}, container{container_}, file{container.GetNvMapFile()} {}
 
 
 nvmap::~nvmap() = default;
 nvmap::~nvmap() = default;
 
 
@@ -63,38 +68,32 @@ void nvmap::OnOpen(DeviceFD fd) {}
 void nvmap::OnClose(DeviceFD fd) {}
 void nvmap::OnClose(DeviceFD fd) {}
 
 
 VAddr nvmap::GetObjectAddress(u32 handle) const {
 VAddr nvmap::GetObjectAddress(u32 handle) const {
-    auto object = GetObject(handle);
-    ASSERT(object);
-    ASSERT(object->status == Object::Status::Allocated);
-    return object->addr;
+    auto obj = file.GetHandle(handle);
+    if (obj) {
+        return obj->address;
+    }
+    return 0;
 }
 }
 
 
-u32 nvmap::CreateObject(u32 size) {
-    // Create a new nvmap object and obtain a handle to it.
-    auto object = std::make_shared<Object>();
-    object->id = next_id++;
-    object->size = size;
-    object->status = Object::Status::Created;
-    object->refcount = 1;
-
-    const u32 handle = next_handle++;
-
-    handles.insert_or_assign(handle, std::move(object));
-
-    return handle;
+std::shared_ptr<NvCore::NvMap::Handle> nvmap::GetObject(u32 handle) const {
+    return file.GetHandle(handle);
 }
 }
 
 
 NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
 NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
     IocCreateParams params;
     IocCreateParams params;
     std::memcpy(&params, input.data(), sizeof(params));
     std::memcpy(&params, input.data(), sizeof(params));
-    LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
-
-    if (!params.size) {
-        LOG_ERROR(Service_NVDRV, "Size is 0");
-        return NvResult::BadValue;
+    LOG_WARNING(Service_NVDRV, "called, size=0x{:08X}", params.size);
+
+    std::shared_ptr<NvCore::NvMap::Handle> handle_description{};
+    auto result =
+        file.CreateHandle(Common::AlignUp(params.size, YUZU_PAGESIZE), handle_description);
+    if (result != NvResult::Success) {
+        LOG_CRITICAL(Service_NVDRV, "Failed to create Object");
+        return result;
     }
     }
-
-    params.handle = CreateObject(params.size);
+    handle_description->orig_size = params.size; // Orig size is the unaligned size
+    params.handle = handle_description->id;
+    LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size);
 
 
     std::memcpy(output.data(), &params, sizeof(params));
     std::memcpy(output.data(), &params, sizeof(params));
     return NvResult::Success;
     return NvResult::Success;
@@ -103,42 +102,42 @@ NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output)
 NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
 NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
     IocAllocParams params;
     IocAllocParams params;
     std::memcpy(&params, input.data(), sizeof(params));
     std::memcpy(&params, input.data(), sizeof(params));
-    LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
+    LOG_WARNING(Service_NVDRV, "called, addr={:X}", params.address);
 
 
     if (!params.handle) {
     if (!params.handle) {
-        LOG_ERROR(Service_NVDRV, "Handle is 0");
+        LOG_CRITICAL(Service_NVDRV, "Handle is 0");
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
     if ((params.align - 1) & params.align) {
     if ((params.align - 1) & params.align) {
-        LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
+        LOG_CRITICAL(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
-    const u32 min_alignment = 0x1000;
-    if (params.align < min_alignment) {
-        params.align = min_alignment;
+    // Force page size alignment at a minimum
+    if (params.align < YUZU_PAGESIZE) {
+        params.align = YUZU_PAGESIZE;
     }
     }
 
 
-    auto object = GetObject(params.handle);
-    if (!object) {
-        LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
+    auto handle_description{file.GetHandle(params.handle)};
+    if (!handle_description) {
+        LOG_CRITICAL(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
-    if (object->status == Object::Status::Allocated) {
-        LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
+    if (handle_description->allocated) {
+        LOG_CRITICAL(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
         return NvResult::InsufficientMemory;
         return NvResult::InsufficientMemory;
     }
     }
 
 
-    object->flags = params.flags;
-    object->align = params.align;
-    object->kind = params.kind;
-    object->addr = params.addr;
-    object->status = Object::Status::Allocated;
-
+    const auto result =
+        handle_description->Alloc(params.flags, params.align, params.kind, params.address);
+    if (result != NvResult::Success) {
+        LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle);
+        return result;
+    }
     std::memcpy(output.data(), &params, sizeof(params));
     std::memcpy(output.data(), &params, sizeof(params));
-    return NvResult::Success;
+    return result;
 }
 }
 
 
 NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
 NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
@@ -147,19 +146,20 @@ NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output)
 
 
     LOG_WARNING(Service_NVDRV, "called");
     LOG_WARNING(Service_NVDRV, "called");
 
 
+    // See the comment in FromId for extra info on this function
     if (!params.handle) {
     if (!params.handle) {
-        LOG_ERROR(Service_NVDRV, "Handle is zero");
+        LOG_CRITICAL(Service_NVDRV, "Error!");
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
-    auto object = GetObject(params.handle);
-    if (!object) {
-        LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
-        return NvResult::BadValue;
+    auto handle_description{file.GetHandle(params.handle)};
+    if (!handle_description) {
+        LOG_CRITICAL(Service_NVDRV, "Error!");
+        return NvResult::AccessDenied; // This will always return EPERM irrespective of if the
+                                       // handle exists or not
     }
     }
 
 
-    params.id = object->id;
-
+    params.id = handle_description->id;
     std::memcpy(output.data(), &params, sizeof(params));
     std::memcpy(output.data(), &params, sizeof(params));
     return NvResult::Success;
     return NvResult::Success;
 }
 }
@@ -168,26 +168,29 @@ NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output)
     IocFromIdParams params;
     IocFromIdParams params;
     std::memcpy(&params, input.data(), sizeof(params));
     std::memcpy(&params, input.data(), sizeof(params));
 
 
-    LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+    LOG_WARNING(Service_NVDRV, "called, id:{}");
 
 
-    auto itr = std::find_if(handles.begin(), handles.end(),
-                            [&](const auto& entry) { return entry.second->id == params.id; });
-    if (itr == handles.end()) {
-        LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
+    // Handles and IDs are always the same value in nvmap however IDs can be used globally given the
+    // right permissions.
+    // Since we don't plan on ever supporting multiprocess we can skip implementing handle refs and
+    // so this function just does simple validation and passes through the handle id.
+    if (!params.id) {
+        LOG_CRITICAL(Service_NVDRV, "Error!");
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
-    auto& object = itr->second;
-    if (object->status != Object::Status::Allocated) {
-        LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
+    auto handle_description{file.GetHandle(params.id)};
+    if (!handle_description) {
+        LOG_CRITICAL(Service_NVDRV, "Error!");
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
-    itr->second->refcount++;
-
-    // Return the existing handle instead of creating a new one.
-    params.handle = itr->first;
-
+    auto result = handle_description->Duplicate(false);
+    if (result != NvResult::Success) {
+        LOG_CRITICAL(Service_NVDRV, "Error!");
+        return result;
+    }
+    params.handle = handle_description->id;
     std::memcpy(output.data(), &params, sizeof(params));
     std::memcpy(output.data(), &params, sizeof(params));
     return NvResult::Success;
     return NvResult::Success;
 }
 }
@@ -198,35 +201,43 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output)
     IocParamParams params;
     IocParamParams params;
     std::memcpy(&params, input.data(), sizeof(params));
     std::memcpy(&params, input.data(), sizeof(params));
 
 
-    LOG_DEBUG(Service_NVDRV, "(STUBBED) called type={}", params.param);
+    LOG_WARNING(Service_NVDRV, "called type={}", params.param);
 
 
-    auto object = GetObject(params.handle);
-    if (!object) {
-        LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
+    if (!params.handle) {
+        LOG_CRITICAL(Service_NVDRV, "Error!");
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
-    if (object->status != Object::Status::Allocated) {
-        LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
+    auto handle_description{file.GetHandle(params.handle)};
+    if (!handle_description) {
+        LOG_CRITICAL(Service_NVDRV, "Error!");
         return NvResult::BadValue;
         return NvResult::BadValue;
     }
     }
 
 
-    switch (static_cast<ParamTypes>(params.param)) {
-    case ParamTypes::Size:
-        params.result = object->size;
+    switch (params.param) {
+    case HandleParameterType::Size:
+        params.result = static_cast<u32_le>(handle_description->orig_size);
+        break;
+    case HandleParameterType::Alignment:
+        params.result = static_cast<u32_le>(handle_description->align);
         break;
         break;
-    case ParamTypes::Alignment:
-        params.result = object->align;
+    case HandleParameterType::Base:
+        params.result = static_cast<u32_le>(-22); // posix EINVAL
         break;
         break;
-    case ParamTypes::Heap:
-        // TODO(Subv): Seems to be a hardcoded value?
-        params.result = 0x40000000;
+    case HandleParameterType::Heap:
+        if (handle_description->allocated)
+            params.result = 0x40000000;
+        else
+            params.result = 0x40000000;
         break;
         break;
-    case ParamTypes::Kind:
-        params.result = object->kind;
+    case HandleParameterType::Kind:
+        params.result = handle_description->kind;
+        break;
+    case HandleParameterType::IsSharedMemMapped:
+        params.result = handle_description->is_shared_mem_mapped;
         break;
         break;
     default:
     default:
-        UNIMPLEMENTED();
+        return NvResult::BadValue;
     }
     }
 
 
     std::memcpy(output.data(), &params, sizeof(params));
     std::memcpy(output.data(), &params, sizeof(params));
@@ -234,46 +245,25 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output)
 }
 }
 
 
 NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
 NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
-    // TODO(Subv): These flags are unconfirmed.
-    enum FreeFlags {
-        Freed = 0,
-        NotFreedYet = 1,
-    };
-
     IocFreeParams params;
     IocFreeParams params;
     std::memcpy(&params, input.data(), sizeof(params));
     std::memcpy(&params, input.data(), sizeof(params));
 
 
-    LOG_DEBUG(Service_NVDRV, "(STUBBED) called");
+    LOG_WARNING(Service_NVDRV, "called");
 
 
-    auto itr = handles.find(params.handle);
-    if (itr == handles.end()) {
-        LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
-        return NvResult::BadValue;
-    }
-    if (!itr->second->refcount) {
-        LOG_ERROR(
-            Service_NVDRV,
-            "There is no references to this object. The object is already freed. handle={:08X}",
-            params.handle);
-        return NvResult::BadValue;
+    if (!params.handle) {
+        LOG_CRITICAL(Service_NVDRV, "Handle null freed?");
+        return NvResult::Success;
     }
     }
 
 
-    itr->second->refcount--;
-
-    params.size = itr->second->size;
-
-    if (itr->second->refcount == 0) {
-        params.flags = Freed;
-        // The address of the nvmap is written to the output if we're finally freeing it, otherwise
-        // 0 is written.
-        params.address = itr->second->addr;
+    if (auto freeInfo{file.FreeHandle(params.handle, false)}) {
+        params.address = freeInfo->address;
+        params.size = static_cast<u32>(freeInfo->size);
+        params.flags = NvCore::NvMap::Handle::Flags{.map_uncached = freeInfo->was_uncached};
     } else {
     } else {
-        params.flags = NotFreedYet;
-        params.address = 0;
+        // This is possible when there's internel dups or other duplicates.
+        LOG_CRITICAL(Service_NVDRV, "Not freed");
     }
     }
 
 
-    handles.erase(params.handle);
-
     std::memcpy(output.data(), &params, sizeof(params));
     std::memcpy(output.data(), &params, sizeof(params));
     return NvResult::Success;
     return NvResult::Success;
 }
 }

+ 25 - 30
src/core/hle/service/nvdrv/devices/nvmap.h

@@ -9,15 +9,23 @@
 #include "common/common_funcs.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "common/swap.h"
+#include "core/hle/service/nvdrv/core/nvmap.h"
 #include "core/hle/service/nvdrv/devices/nvdevice.h"
 #include "core/hle/service/nvdrv/devices/nvdevice.h"
 
 
+namespace Service::Nvidia::NvCore {
+class Container;
+} // namespace Service::Nvidia::NvCore
+
 namespace Service::Nvidia::Devices {
 namespace Service::Nvidia::Devices {
 
 
 class nvmap final : public nvdevice {
 class nvmap final : public nvdevice {
 public:
 public:
-    explicit nvmap(Core::System& system_);
+    explicit nvmap(Core::System& system_, NvCore::Container& container);
     ~nvmap() override;
     ~nvmap() override;
 
 
+    nvmap(nvmap const&) = delete;
+    nvmap& operator=(nvmap const&) = delete;
+
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
     NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
                     std::vector<u8>& output) override;
                     std::vector<u8>& output) override;
     NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
     NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -31,27 +39,16 @@ public:
     /// Returns the allocated address of an nvmap object given its handle.
     /// Returns the allocated address of an nvmap object given its handle.
     VAddr GetObjectAddress(u32 handle) const;
     VAddr GetObjectAddress(u32 handle) const;
 
 
-    /// Represents an nvmap object.
-    struct Object {
-        enum class Status { Created, Allocated };
-        u32 id;
-        u32 size;
-        u32 flags;
-        u32 align;
-        u8 kind;
-        VAddr addr;
-        Status status;
-        u32 refcount;
-        u32 dma_map_addr;
-    };
+    std::shared_ptr<NvCore::NvMap::Handle> GetObject(u32 handle) const;
 
 
-    std::shared_ptr<Object> GetObject(u32 handle) const {
-        auto itr = handles.find(handle);
-        if (itr != handles.end()) {
-            return itr->second;
-        }
-        return {};
-    }
+    enum class HandleParameterType : u32_le {
+        Size = 1,
+        Alignment = 2,
+        Base = 3,
+        Heap = 4,
+        Kind = 5,
+        IsSharedMemMapped = 6
+    };
 
 
 private:
 private:
     /// Id to use for the next handle that is created.
     /// Id to use for the next handle that is created.
@@ -60,9 +57,6 @@ private:
     /// Id to use for the next object that is created.
     /// Id to use for the next object that is created.
     u32 next_id = 0;
     u32 next_id = 0;
 
 
-    /// Mapping of currently allocated handles to the objects they represent.
-    std::unordered_map<u32, std::shared_ptr<Object>> handles;
-
     struct IocCreateParams {
     struct IocCreateParams {
         // Input
         // Input
         u32_le size{};
         u32_le size{};
@@ -83,11 +77,11 @@ private:
         // Input
         // Input
         u32_le handle{};
         u32_le handle{};
         u32_le heap_mask{};
         u32_le heap_mask{};
-        u32_le flags{};
+        NvCore::NvMap::Handle::Flags flags{};
         u32_le align{};
         u32_le align{};
         u8 kind{};
         u8 kind{};
         INSERT_PADDING_BYTES(7);
         INSERT_PADDING_BYTES(7);
-        u64_le addr{};
+        u64_le address{};
     };
     };
     static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");
     static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");
 
 
@@ -96,14 +90,14 @@ private:
         INSERT_PADDING_BYTES(4);
         INSERT_PADDING_BYTES(4);
         u64_le address{};
         u64_le address{};
         u32_le size{};
         u32_le size{};
-        u32_le flags{};
+        NvCore::NvMap::Handle::Flags flags{};
     };
     };
     static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
     static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
 
 
     struct IocParamParams {
     struct IocParamParams {
         // Input
         // Input
         u32_le handle{};
         u32_le handle{};
-        u32_le param{};
+        HandleParameterType param{};
         // Output
         // Output
         u32_le result{};
         u32_le result{};
     };
     };
@@ -117,14 +111,15 @@ private:
     };
     };
     static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
     static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
 
 
-    u32 CreateObject(u32 size);
-
     NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
     NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
+
+    NvCore::Container& container;
+    NvCore::NvMap& file;
 };
 };
 
 
 } // namespace Service::Nvidia::Devices
 } // namespace Service::Nvidia::Devices

+ 6 - 9
src/core/hle/service/nvdrv/nvdrv.cpp

@@ -138,21 +138,18 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
 
 
 Module::Module(Core::System& system)
 Module::Module(Core::System& system)
     : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} {
     : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} {
-    auto nvmap_dev = std::make_shared<Devices::nvmap>(system);
-    devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev);
+    devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, container);
     devices["/dev/nvhost-gpu"] =
     devices["/dev/nvhost-gpu"] =
-        std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev, events_interface, container);
+        std::make_shared<Devices::nvhost_gpu>(system, events_interface, container);
     devices["/dev/nvhost-ctrl-gpu"] =
     devices["/dev/nvhost-ctrl-gpu"] =
         std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface);
         std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface);
-    devices["/dev/nvmap"] = nvmap_dev;
-    devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev);
+    devices["/dev/nvmap"] = std::make_shared<Devices::nvmap>(system, container);
+    devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, container);
     devices["/dev/nvhost-ctrl"] =
     devices["/dev/nvhost-ctrl"] =
         std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container);
         std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container);
-    devices["/dev/nvhost-nvdec"] =
-        std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev, container);
+    devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, container);
     devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system);
     devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system);
-    devices["/dev/nvhost-vic"] =
-        std::make_shared<Devices::nvhost_vic>(system, nvmap_dev, container);
+    devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, container);
 }
 }
 
 
 Module::~Module() = default;
 Module::~Module() = default;