diff options
author | Fernando Sahmkow <fsahmkow27@gmail.com> | 2021-11-04 12:51:17 +0100 |
---|---|---|
committer | Fernando Sahmkow <fsahmkow27@gmail.com> | 2022-10-06 21:00:51 +0200 |
commit | de0e8eff429b4374c18e3325ad3747db55bddddd (patch) | |
tree | 6700091146d5282c1efbee40c94b6573c5b2895f /src/core/hle | |
parent | NVDRV: Refactor and add new NvMap. (diff) | |
download | yuzu-de0e8eff429b4374c18e3325ad3747db55bddddd.tar yuzu-de0e8eff429b4374c18e3325ad3747db55bddddd.tar.gz yuzu-de0e8eff429b4374c18e3325ad3747db55bddddd.tar.bz2 yuzu-de0e8eff429b4374c18e3325ad3747db55bddddd.tar.lz yuzu-de0e8eff429b4374c18e3325ad3747db55bddddd.tar.xz yuzu-de0e8eff429b4374c18e3325ad3747db55bddddd.tar.zst yuzu-de0e8eff429b4374c18e3325ad3747db55bddddd.zip |
Diffstat (limited to 'src/core/hle')
18 files changed, 307 insertions, 277 deletions
diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index d3f227f52..281381cc4 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/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); // Handles cannot be allocated twice - if (allocated) [[unlikely]] + if (allocated) return NvResult::AccessDenied; flags = pFlags; @@ -61,33 +61,34 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) { 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); - 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 - 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 /* - 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 - if (handleDesc.dupes == 0 && handleDesc.internal_dupes == 0) { + if (handle_description.dupes == 0 && handle_description.internal_dupes == 0) { std::scoped_lock lock(handles_lock); - auto it{handles.find(handleDesc.id)}; + auto it{handles.find(handle_description.id)}; if (it != handles.end()) handles.erase(it); @@ -102,10 +103,10 @@ NvResult NvMap::CreateHandle(u64 size, std::shared_ptr<NvMap::Handle>& result_ou return NvResult::BadValue; 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; } @@ -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) { UNIMPLEMENTED_MSG("pinning"); return 0; /* - auto handleDesc{GetHandle(handle)}; - if (!handleDesc) + auto handle_description{GetHandle(handle)}; + if (!handle_description) [[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 // mapped { // Lock now to prevent our queue entry from being removed for allocation in-between the // following check and erase 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 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 std::scoped_lock queueLock(unmap_queue_lock); if (auto freeHandleDesc{unmap_queue.front()}) { // Handles in the unmap queue are guaranteed not to be pinned so don't bother // checking if they are before unmapping std::scoped_lock freeLock(freeHandleDesc->mutex); - if (handleDesc->pin_virt_address) + if (handle_description->pin_virt_address) UnmapHandle(*freeHandleDesc); } else { 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) { UNIMPLEMENTED_MSG("Unpinning"); /* - auto handleDesc{GetHandle(handle)}; - if (!handleDesc) + auto handle_description{GetHandle(handle)}; + if (!handle_description) 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!"); - } else if (!handleDesc->pins) { + } else if (!handle_description->pins) { std::scoped_lock queueLock(unmap_queue_lock); // 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 // 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 (--handleDesc->internal_dupes < 0) + if (--handle_description->internal_dupes < 0) LOG_WARNING(Service_NVDRV, "Internal duplicate count imbalance detected!"); } else { - if (--handleDesc->dupes < 0) { + if (--handle_description->dupes < 0) { LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); - } else if (handleDesc->dupes == 0) { + } else if (handle_description->dupes == 0) { // Force unmap the handle - if (handleDesc->pin_virt_address) { + if (handle_description->pin_virt_address) { 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 - // 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 - LOG_ERROR(Service_NVDRV, + LOG_DEBUG(Service_NVDRV, "Tried to free nvmap handle: {} but didn't as it still has duplicates", handle); 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 { return std::nullopt; diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index e47aa755d..994c70e6f 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -59,6 +59,8 @@ public: u8 kind{}; //!< Used for memory compression bool allocated{}; //!< If the handle has been allocated with `Alloc` + u64 dma_map_addr{}; //! remove me after implementing pinning. + Handle(u64 size, Id id); /** @@ -101,16 +103,16 @@ private: /** * @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 - * @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 */ - bool TryRemoveHandle(const Handle& handleDesc); + bool TryRemoveHandle(const Handle& handle_description); public: /** @@ -131,6 +133,8 @@ public: std::shared_ptr<Handle> GetHandle(Handle::Id handle); + VAddr GetHandleAddress(Handle::Id handle); + /** * @brief Maps a handle into the SMMU address space * @note This operation is refcounted, the number of calls to this must eventually match the diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 604711914..b1c0e9eb2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -5,15 +5,16 @@ #include "common/logging/log.h" #include "core/core.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/nvmap.h" #include "core/perf_stats.h" #include "video_core/gpu.h" 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; 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, u32 height, u32 stride, android::BufferTransformFlags transform, const Common::Rectangle<int>& crop_rect) { - const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); + const VAddr addr = nvmap.GetHandleAddress(buffer_handle); LOG_TRACE(Service, "Drawing from address {:X} offset {:08X} 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(); } +Kernel::KEvent* nvdisp_disp0::QueryEvent(u32 event_id) { + LOG_CRITICAL(Service_NVDRV, "Unknown DISP Event {}", event_id); + return nullptr; +} + } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 67b105e02..1ca9b2e74 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/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/pixel_format.h" +namespace Service::Nvidia::NvCore { +class Container; +class NvMap; +} // namespace Service::Nvidia::NvCore + namespace Service::Nvidia::Devices { class nvmap; class nvdisp_disp0 final : public nvdevice { 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; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, @@ -35,8 +40,11 @@ public: u32 stride, android::BufferTransformFlags transform, const Common::Rectangle<int>& crop_rect); + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: - std::shared_ptr<nvmap> nvmap_dev; + NvCore::Container& container; + NvCore::NvMap& nvmap; }; } // namespace Service::Nvidia::Devices 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 9867a648d..9283d6aec 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -7,15 +7,16 @@ #include "common/assert.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/nvhost_as_gpu.h" -#include "core/hle/service/nvdrv/devices/nvmap.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" 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; 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}", 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) { LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); 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 size{static_cast<u64>(entry.pages) << 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) { 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.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(), ¶ms, 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(); - - u64 page_size{params.page_size}; - if (!page_size) { - page_size = object->align; - } - if ((params.flags & AddressSpaceFlags::Remap) != AddressSpaceFlags::None) { if (const auto buffer_map{FindBufferMap(params.offset)}; buffer_map) { 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(), ¶ms, 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}; if (!size) { size = object->size; @@ -363,4 +362,9 @@ std::optional<std::size_t> nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) { 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 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 555843a6f..67d2f1e87 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -13,6 +13,11 @@ #include "common/swap.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 { constexpr u32 DEFAULT_BIG_PAGE_SIZE = 1 << 16; @@ -29,7 +34,7 @@ DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags); class nvhost_as_gpu final : public nvdevice { 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; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, @@ -42,6 +47,8 @@ public: void OnOpen(DeviceFD fd) override; void OnClose(DeviceFD fd) override; + Kernel::KEvent* QueryEvent(u32 event_id) override; + private: class BufferMap final { public: @@ -180,7 +187,8 @@ private: 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::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 std::map<GPUVAddr, BufferMap> buffer_mappings; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 5e2155e6c..51c40f620 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/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]); return events_interface.events[slot]; } + // Is this possible in hardware? + ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id); return nullptr; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index a480bfc47..e7921ade2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -6,6 +6,7 @@ #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/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -22,10 +23,10 @@ Tegra::CommandHeader BuildFenceAction(Tegra::GPU::FenceOperation op, u32 syncpoi } } // 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.value = system_.GPU().GetSyncpointValue(channel_fence.id); sm_exception_breakpoint_int_report_event = diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 4f73a7bae..440c0c42d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -17,6 +17,7 @@ namespace Service::Nvidia { namespace NvCore { class Container; +class NvMap; class SyncpointManager; } // namespace NvCore @@ -28,8 +29,8 @@ namespace Service::Nvidia::Devices { class nvmap; class nvhost_gpu final : public nvdevice { 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; 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 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); - std::shared_ptr<nvmap> nvmap_dev; EventInterface& events_interface; NvCore::Container& core; NvCore::SyncpointManager& syncpoint_manager; + NvCore::NvMap& nvmap; NvFence channel_fence; // Events diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 2c9158c7c..aa1a00832 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -10,9 +10,8 @@ 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; NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 04da4a913..fef4b3216 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/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 { 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; NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 5a9c59f37..e76c9e5ed 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -9,9 +9,9 @@ #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/core/syncpoint_manager.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h" -#include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/memory.h" #include "video_core/memory_manager.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 -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; 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) { - 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;); 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)); 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) { IoctlGetWaitbase params{}; + LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); params.value = 0; // Seems to be hard coded at 0 std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); @@ -141,7 +141,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto auto& gpu = system.GPU(); 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) { LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmd_buffer.map_handle); std::memcpy(output.data(), ¶ms, output.size()); @@ -150,7 +150,8 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto if (object->dma_map_addr == 0) { // 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 - 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); // Ensure that the dma_map_addr is indeed in the lower 32-bit address space. 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) { LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size); } 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(), ¶ms, sizeof(IoctlMapBuffer)); @@ -184,4 +185,9 @@ NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, 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 diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index cccc94a58..74231d5c5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -11,17 +11,16 @@ namespace Service::Nvidia { namespace NvCore { -class SyncpointManager; class Container; +class NvMap; +class SyncpointManager; } // namespace NvCore namespace Devices { -class nvmap; class nvhost_nvdec_common : public nvdevice { 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; protected: @@ -114,12 +113,14 @@ protected: NvResult UnmapBuffer(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{}; s32_le nvmap_fd{}; u32_le submit_timeout{}; - std::shared_ptr<nvmap> nvmap_dev; NvCore::Container& core; NvCore::SyncpointManager& syncpoint_manager; + NvCore::NvMap& nvmap; std::array<u32, MaxSyncPoints> device_syncpoints{}; }; }; // namespace Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 66558c331..358e89aa8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -8,9 +8,8 @@ #include "video_core/renderer_base.h" 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; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 6f9838b2d..252b1e6f2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/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 { 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(); NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index d8518149d..2aee68f5c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -2,19 +2,24 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> +#include <bit> #include <cstring> +#include "common/alignment.h" #include "common/assert.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/memory.h" + +using Core::Memory::YUZU_PAGESIZE; 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; @@ -63,38 +68,32 @@ void nvmap::OnOpen(DeviceFD fd) {} void nvmap::OnClose(DeviceFD fd) {} 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) { IocCreateParams params; std::memcpy(¶ms, 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(), ¶ms, sizeof(params)); 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) { IocAllocParams params; std::memcpy(¶ms, 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) { - LOG_ERROR(Service_NVDRV, "Handle is 0"); + LOG_CRITICAL(Service_NVDRV, "Handle is 0"); return NvResult::BadValue; } 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; } - 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; } - 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; } - 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(), ¶ms, sizeof(params)); - return NvResult::Success; + return result; } 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"); + // See the comment in FromId for extra info on this function if (!params.handle) { - LOG_ERROR(Service_NVDRV, "Handle is zero"); + LOG_CRITICAL(Service_NVDRV, "Error!"); 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(), ¶ms, sizeof(params)); return NvResult::Success; } @@ -168,26 +168,29 @@ NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) IocFromIdParams params; std::memcpy(¶ms, 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; } - 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; } - 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(), ¶ms, sizeof(params)); return NvResult::Success; } @@ -198,35 +201,43 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) IocParamParams params; std::memcpy(¶ms, 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; } - 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; } - 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; - case ParamTypes::Alignment: - params.result = object->align; + case HandleParameterType::Base: + params.result = static_cast<u32_le>(-22); // posix EINVAL 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; - 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; default: - UNIMPLEMENTED(); + return NvResult::BadValue; } std::memcpy(output.data(), ¶ms, 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) { - // TODO(Subv): These flags are unconfirmed. - enum FreeFlags { - Freed = 0, - NotFreedYet = 1, - }; - IocFreeParams params; std::memcpy(¶ms, 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 { - 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(), ¶ms, sizeof(params)); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index d5360d6e5..c22eb57a4 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -9,15 +9,23 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" +#include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" +namespace Service::Nvidia::NvCore { +class Container; +} // namespace Service::Nvidia::NvCore + namespace Service::Nvidia::Devices { class nvmap final : public nvdevice { public: - explicit nvmap(Core::System& system_); + explicit nvmap(Core::System& system_, NvCore::Container& container); ~nvmap() override; + nvmap(nvmap const&) = delete; + nvmap& operator=(nvmap const&) = delete; + NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 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. 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: /// 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. 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 { // Input u32_le size{}; @@ -83,11 +77,11 @@ private: // Input u32_le handle{}; u32_le heap_mask{}; - u32_le flags{}; + NvCore::NvMap::Handle::Flags flags{}; u32_le align{}; u8 kind{}; INSERT_PADDING_BYTES(7); - u64_le addr{}; + u64_le address{}; }; static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); @@ -96,14 +90,14 @@ private: INSERT_PADDING_BYTES(4); u64_le address{}; u32_le size{}; - u32_le flags{}; + NvCore::NvMap::Handle::Flags flags{}; }; static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); struct IocParamParams { // Input u32_le handle{}; - u32_le param{}; + HandleParameterType param{}; // Output u32_le result{}; }; @@ -117,14 +111,15 @@ private: }; 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 IocAlloc(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 IocParam(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 diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 824c0e290..f4914d539 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -138,21 +138,18 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger Module::Module(Core::System& system) : 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"] = - 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"] = 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"] = 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-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; |