From 2f0418c10134b4c8e5ae47ace623b5db57c0435c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 21 Dec 2023 00:04:03 +0100 Subject: Core: Initial implementation of device memory mapping --- src/core/device_memory.h | 16 ++ src/core/device_memory_manager.h | 97 ++++++++++++ src/core/device_memory_manager.inc | 304 +++++++++++++++++++++++++++++++++++++ 3 files changed, 417 insertions(+) create mode 100644 src/core/device_memory_manager.h create mode 100644 src/core/device_memory_manager.inc (limited to 'src/core') diff --git a/src/core/device_memory.h b/src/core/device_memory.h index 13388b73e..11bf0e326 100644 --- a/src/core/device_memory.h +++ b/src/core/device_memory.h @@ -31,6 +31,12 @@ public: DramMemoryMap::Base; } + template + PAddr GetRawPhysicalAddr(const T* ptr) const { + return static_cast(reinterpret_cast(ptr) - + reinterpret_cast(buffer.BackingBasePointer())); + } + template T* GetPointer(Common::PhysicalAddress addr) { return reinterpret_cast(buffer.BackingBasePointer() + @@ -43,6 +49,16 @@ public: (GetInteger(addr) - DramMemoryMap::Base)); } + template + T* GetPointerFromRaw(PAddr addr) { + return reinterpret_cast(buffer.BackingBasePointer() + addr); + } + + template + const T* GetPointerFromRaw(PAddr addr) const { + return reinterpret_cast(buffer.BackingBasePointer() + addr); + } + Common::HostMemory buffer; }; diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h new file mode 100644 index 000000000..0861b792d --- /dev/null +++ b/src/core/device_memory_manager.h @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "common/virtual_buffer.h" + +namespace Core { + +class DeviceMemory; + +namespace Memory { +class Memory; +} + +template +struct DeviceMemoryManagerAllocator; + +template +class DeviceMemoryManager { + using DeviceInterface = typename Traits::DeviceInterface; + +public: + DeviceMemoryManager(const DeviceMemory& device_memory); + ~DeviceMemoryManager(); + + void BindInterface(DeviceInterface* interface); + + DAddr Allocate(size_t size); + void AllocateFixed(DAddr start, size_t size); + DAddr AllocatePinned(size_t size); + void Free(DAddr start, size_t size); + + void Map(DAddr address, VAddr virtual_address, size_t size, size_t p_id); + void Unmap(DAddr address, size_t size); + + // Write / Read + template + T* GetPointer(DAddr address); + + template + const T* GetPointer(DAddr address) const; + + template + void Write(DAddr address, T value); + + template + T Read(DAddr address) const; + + void ReadBlock(DAddr address, void* dest_pointer, size_t size); + void WriteBlock(DAddr address, void* src_pointer, size_t size); + + size_t RegisterProcess(Memory::Memory* memory); + void UnregisterProcess(size_t id); + +private: + static constexpr bool supports_pinning = Traits::supports_pinning; + static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; + static constexpr size_t device_as_size = 1ULL << device_virtual_bits; + static constexpr size_t physical_max_bits = 33; + static constexpr size_t page_bits = 12; + static constexpr u32 physical_address_base = 1U << page_bits; + + template + T* GetPointerFromRaw(PAddr addr) { + return reinterpret_cast(physical_base + addr); + } + + template + const T* GetPointerFromRaw(PAddr addr) const { + return reinterpret_cast(physical_base + addr); + } + + template + PAddr GetRawPhysicalAddr(const T* ptr) const { + return static_cast(reinterpret_cast(ptr) - physical_base); + } + + void WalkBlock(const DAddr addr, const std::size_t size, auto on_unmapped, auto on_memory, + auto increment); + + std::unique_ptr> impl; + + const uintptr_t physical_base; + DeviceInterface* interface; + Common::VirtualBuffer compressed_physical_ptr; + Common::VirtualBuffer compressed_device_addr; + + std::deque id_pool; + std::deque registered_processes; +}; + +} // namespace Core \ No newline at end of file diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc new file mode 100644 index 000000000..1f52b92d5 --- /dev/null +++ b/src/core/device_memory_manager.inc @@ -0,0 +1,304 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "common/address_space.h" +#include "common/address_space.inc" +#include "common/alignment.h" +#include "common/scope_exit.h" +#include "core/device_memory.h" +#include "core/device_memory_manager.h" +#include "core/memory.h" + +namespace Core { + +struct EmptyAllocator { + EmptyAllocator([[maybe_unused]] DAddr address) {} +}; + +template +struct DeviceMemoryManagerAllocator { + static constexpr bool supports_pinning = DTraits::supports_pinning; + static constexpr size_t device_virtual_bits = DTraits::device_virtual_bits; + static constexpr size_t pin_bits = 32; + static constexpr DAddr first_address = 1ULL << Memory::YUZU_PAGEBITS; + static constexpr DAddr max_pin_area = supports_pinning ? 1ULL << pin_bits : first_address; + static constexpr DAddr max_device_area = 1ULL << device_virtual_bits; + + DeviceMemoryManagerAllocator() + : pin_allocator(first_address), + main_allocator(supports_pinning ? 1ULL << pin_bits : first_address) {} + + std::conditional_t, EmptyAllocator> + pin_allocator; + Common::FlatAllocator main_allocator; + + /// Returns true when vaddr -> vaddr+size is fully contained in the buffer + template + [[nodiscard]] bool IsInBounds(VAddr addr, u64 size) const noexcept { + if constexpr (pin_area) { + return addr >= 0 && addr + size <= max_pin_area; + } else { + return addr >= max_pin_area && addr + size <= max_device_area; + } + } + + DAddr Allocate(size_t size) { + return main_allocator.Allocate(size); + } + + DAddr AllocatePinned(size_t size) { + return pin_allocator.Allocate(size); + } + + void DoInRange(DAddr address, size_t size, auto pin_func, auto main_func) { + if (IsInBounds(address, size)) { + pin_func(address, size); + return; + } + if (IsInBounds(address, size)) { + main_func(address, size); + return; + } + DAddr end_size = address + size - max_pin_area; + DAddr end_size2 = max_pin_area - address; + pin_func(address, end_size2); + main_func(max_pin_area, end_size); + } + + void AllocateFixed(DAddr b_address, size_t b_size) { + if constexpr (supports_pinning) { + DoInRange( + b_address, b_size, + [this](DAddr address, size_t size) { pin_allocator.AllocateFixed(address, size); }, + [this](DAddr address, size_t size) { + main_allocator.AllocateFixed(address, size); + }); + } else { + main_allocator.AllocateFixed(b_address, b_size); + } + } + + void Free(DAddr b_address, size_t b_size) { + if constexpr (supports_pinning) { + DoInRange( + b_address, b_size, + [this](DAddr address, size_t size) { pin_allocator.Free(address, size); }, + [this](DAddr address, size_t size) { main_allocator.Free(address, size); }); + } else { + main_allocator.Free(b_address, b_size); + } + } +}; + +template +DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memory_) + : physical_base{reinterpret_cast(device_memory_.buffer.BackingBasePointer())}, + interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), + compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)) { + impl = std::make_unique>(); +} + +template +DeviceMemoryManager::~DeviceMemoryManager() = default; + +template +void DeviceMemoryManager::BindInterface(DeviceInterface* interface_) { + interface = interface_; +} + +template +DAddr DeviceMemoryManager::Allocate(size_t size) { + return impl->Allocate(size); +} + +template +void DeviceMemoryManager::AllocateFixed(DAddr start, size_t size) { + return impl->AllocateFixed(start, size); +} + +template +DAddr DeviceMemoryManager::AllocatePinned(size_t size) { + return impl->AllocatePinned(size); +} + +template +void DeviceMemoryManager::Free(DAddr start, size_t size) { + impl->Free(start, size); +} + +template +void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size_t size, + size_t p_id) { + Core::Memory::Memory* process_memory = registered_processes[p_id]; + size_t start_page_d = address >> Memory::YUZU_PAGEBITS; + size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; + std::atomic_thread_fence(std::memory_order_acquire); + for (size_t i = 0; i < num_pages; i++) { + auto* ptr = process_memory->GetPointer( + Common::ProcessAddress(virtual_address + i * Memory::YUZU_PAGESIZE)); + if (ptr == nullptr) [[unlikely]] { + compressed_physical_ptr[start_page_d + i] = 0; + continue; + } + auto phys_addr = static_cast(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U; + compressed_physical_ptr[start_page_d + i] = phys_addr; + compressed_device_addr[phys_addr - 1U] = static_cast(start_page_d + i); + } + std::atomic_thread_fence(std::memory_order_release); +} + +template +void DeviceMemoryManager::Unmap(DAddr address, size_t size) { + size_t start_page_d = address >> Memory::YUZU_PAGEBITS; + size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; + std::atomic_thread_fence(std::memory_order_acquire); + for (size_t i = 0; i < num_pages; i++) { + auto phys_addr = compressed_physical_ptr[start_page_d + i]; + compressed_physical_ptr[start_page_d + i] = 0; + if (phys_addr != 0) { + compressed_device_addr[phys_addr - 1] = 0; + } + } + std::atomic_thread_fence(std::memory_order_release); +} + +template +template +T* DeviceMemoryManager::GetPointer(DAddr address) { + const size_t index = address >> Memory::YUZU_PAGEBITS; + const size_t offset = address & Memory::YUZU_PAGEMASK; + auto phys_addr = compressed_physical_ptr[index]; + if (phys_addr == 0) [[unlikely]] { + return nullptr; + } + return GetPointerFromRaw( + static_cast(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset)); +} + +template +template +const T* DeviceMemoryManager::GetPointer(DAddr address) const { + const size_t index = address >> Memory::YUZU_PAGEBITS; + const size_t offset = address & Memory::YUZU_PAGEMASK; + auto phys_addr = compressed_physical_ptr[index]; + if (phys_addr == 0) [[unlikely]] { + return nullptr; + } + return GetPointerFromRaw( + static_cast(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset)); +} + +template +template +void DeviceMemoryManager::Write(DAddr address, T value) { + T* ptr = GetPointer(address); + if (!ptr) [[unlikely]] { + return; + } + std::memcpy(ptr, &value, sizeof(T)); +} + +template +template +T DeviceMemoryManager::Read(DAddr address) const { + const T* ptr = GetPointer(address); + T result{}; + if (!ptr) [[unlikely]] { + return result; + } + std::memcpy(&result, ptr, sizeof(T)); + return result; +} + +template +void DeviceMemoryManager::WalkBlock(DAddr addr, std::size_t size, auto on_unmapped, + auto on_memory, auto increment) { + std::size_t remaining_size = size; + std::size_t page_index = addr >> Memory::YUZU_PAGEBITS; + std::size_t page_offset = addr & Memory::YUZU_PAGEMASK; + + while (remaining_size) { + const std::size_t copy_amount = + std::min(static_cast(Memory::YUZU_PAGESIZE) - page_offset, remaining_size); + const auto current_vaddr = + static_cast((page_index << Memory::YUZU_PAGEBITS) + page_offset); + SCOPE_EXIT({ + page_index++; + page_offset = 0; + increment(copy_amount); + remaining_size -= copy_amount; + }); + + auto phys_addr = compressed_physical_ptr[page_index]; + if (phys_addr == 0) { + on_unmapped(copy_amount, current_vaddr); + continue; + } + auto* mem_ptr = GetPointerFromRaw( + static_cast(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset)); + on_memory(copy_amount, mem_ptr); + } +} + +template +void DeviceMemoryManager::ReadBlock(DAddr address, void* dest_pointer, size_t size) { + WalkBlock( + address, size, + [&](size_t copy_amount, DAddr current_vaddr) { + LOG_ERROR( + HW_Memory, + "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, address, size); + std::memset(dest_pointer, 0, copy_amount); + }, + [&](size_t copy_amount, const u8* const src_ptr) { + std::memcpy(dest_pointer, src_ptr, copy_amount); + }, + [&](const std::size_t copy_amount) { + dest_pointer = static_cast(dest_pointer) + copy_amount; + }); +} + +template +void DeviceMemoryManager::WriteBlock(DAddr address, void* src_pointer, size_t size) { + WalkBlock( + address, size, + [&](size_t copy_amount, DAddr current_vaddr) { + LOG_ERROR( + HW_Memory, + "Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, address, size); + }, + [&](size_t copy_amount, u8* const dst_ptr) { + std::memcpy(dst_ptr, src_pointer, copy_amount); + }, + [&](const std::size_t copy_amount) { + src_pointer = static_cast(src_pointer) + copy_amount; + }); +} + +template +size_t DeviceMemoryManager::RegisterProcess(Memory::Memory* memory_interface) { + size_t new_id; + if (!id_pool.empty()) { + new_id = id_pool.front(); + id_pool.pop_front(); + registered_processes[new_id] = memory_interface; + } else { + registered_processes.emplace_back(memory_interface); + new_id = registered_processes.size() - 1U; + } + return new_id; +} + +template +void DeviceMemoryManager::UnregisterProcess(size_t id) { + registered_processes[id] = nullptr; + id_pool.push_front(id); +} + +} // namespace Core \ No newline at end of file -- cgit v1.2.3 From 7a9d1ad2f873003e6aad637e8749b77b91247da3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 24 Dec 2023 18:20:02 +0100 Subject: NVDRV: Implement sessions and initial implementation of SMMU --- src/core/hle/service/hle_ipc.h | 8 +++ src/core/hle/service/nvdrv/core/container.cpp | 44 +++++++++++++++- src/core/hle/service/nvdrv/core/container.h | 15 ++++++ src/core/hle/service/nvdrv/core/nvmap.cpp | 58 ++++++++++++++++------ src/core/hle/service/nvdrv/core/nvmap.h | 16 ++++-- src/core/hle/service/nvdrv/devices/nvdevice.h | 2 +- .../hle/service/nvdrv/devices/nvdisp_disp0.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 2 +- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 2 +- .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 2 +- .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 2 +- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 9 +++- src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 2 +- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 4 +- .../service/nvdrv/devices/nvhost_nvdec_common.h | 5 +- .../hle/service/nvdrv/devices/nvhost_nvjpg.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 10 +++- src/core/hle/service/nvdrv/devices/nvhost_vic.h | 2 +- src/core/hle/service/nvdrv/devices/nvmap.cpp | 31 +++++++----- src/core/hle/service/nvdrv/devices/nvmap.h | 7 +-- src/core/hle/service/nvdrv/nvdrv.cpp | 27 ++++++---- src/core/hle/service/nvdrv/nvdrv.h | 6 ++- src/core/hle/service/nvdrv/nvdrv_interface.cpp | 36 +++++++++++--- src/core/hle/service/nvdrv/nvdrv_interface.h | 1 + .../service/nvnflinger/fb_share_buffer_manager.cpp | 21 ++++---- .../service/nvnflinger/fb_share_buffer_manager.h | 5 +- src/core/hle/service/nvnflinger/nvnflinger.cpp | 2 +- 33 files changed, 252 insertions(+), 83 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 440737db5..d550a11b7 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h @@ -19,6 +19,8 @@ #include "core/hle/ipc.h" #include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/svc_common.h" +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_handle_table.h" union Result; @@ -41,6 +43,8 @@ class KernelCore; class KHandleTable; class KProcess; class KServerSession; +template +class KScopedAutoObject; class KThread; } // namespace Kernel @@ -373,6 +377,10 @@ public: return nullptr; } + Kernel::KScopedAutoObject GetObjectFromHandle(u32 handle) { + return GetClientHandleTable().GetObjectForIpc(handle, thread); + } + [[nodiscard]] std::shared_ptr GetManager() const { return manager.lock(); } diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index 37ca24f5d..7c2231fe6 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -2,19 +2,30 @@ // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors // SPDX-License-Identifier: GPL-3.0-or-later +#include +#include +#include + +#include "core/hle/kernel/k_process.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/memory.h" #include "video_core/host1x/host1x.h" namespace Service::Nvidia::NvCore { struct ContainerImpl { explicit ContainerImpl(Tegra::Host1x::Host1x& host1x_) - : file{host1x_}, manager{host1x_}, device_file_data{} {} + : host1x{host1x_}, file{host1x_}, manager{host1x_}, device_file_data{} {} + Tegra::Host1x::Host1x& host1x; NvMap file; SyncpointManager manager; Container::Host1xDeviceFileData device_file_data; + std::deque sessions; + size_t new_ids{}; + std::deque id_pool; + std::mutex session_guard; }; Container::Container(Tegra::Host1x::Host1x& host1x_) { @@ -23,6 +34,37 @@ Container::Container(Tegra::Host1x::Host1x& host1x_) { Container::~Container() = default; +size_t Container::OpenSession(Kernel::KProcess* process) { + std::scoped_lock lk(impl->session_guard); + size_t new_id{}; + auto* memory_interface = &process->GetMemory(); + auto& smmu = impl->host1x.MemoryManager(); + auto smmu_id = smmu.RegisterProcess(memory_interface); + if (!impl->id_pool.empty()) { + new_id = impl->id_pool.front(); + impl->id_pool.pop_front(); + impl->sessions[new_id] = Session{new_id, process, smmu_id}; + } else { + impl->sessions.emplace_back(new_id, process, smmu_id); + new_id = impl->new_ids++; + } + LOG_CRITICAL(Debug, "Created Session {}", new_id); + return new_id; +} + +void Container::CloseSession(size_t id) { + std::scoped_lock lk(impl->session_guard); + auto& smmu = impl->host1x.MemoryManager(); + smmu.UnregisterProcess(impl->sessions[id].smmu_id); + impl->id_pool.emplace_front(id); + LOG_CRITICAL(Debug, "Closed Session {}", id); +} + +Session* Container::GetSession(size_t id) { + std::atomic_thread_fence(std::memory_order_acquire); + return &impl->sessions[id]; +} + NvMap& Container::GetNvMapFile() { return impl->file; } diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index b4b63ac90..a1fd20199 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -10,6 +10,10 @@ #include "core/hle/service/nvdrv/nvdata.h" +namespace Kernel { +class KProcess; +} + namespace Tegra::Host1x { class Host1x; } // namespace Tegra::Host1x @@ -21,11 +25,22 @@ class SyncpointManager; struct ContainerImpl; +struct Session { + size_t id; + Kernel::KProcess* process; + size_t smmu_id; +}; + class Container { public: explicit Container(Tegra::Host1x::Host1x& host1x); ~Container(); + size_t OpenSession(Kernel::KProcess* process); + void CloseSession(size_t id); + + Session* GetSession(size_t id); + NvMap& GetNvMapFile(); const NvMap& GetNvMapFile() const; diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 0ca05257e..fd6c9aa0c 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -18,8 +18,6 @@ NvMap::Handle::Handle(u64 size_, Id id_) } NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { - std::scoped_lock lock(mutex); - // Handles cannot be allocated twice if (allocated) { return NvResult::AccessDenied; @@ -79,10 +77,11 @@ void NvMap::UnmapHandle(Handle& handle_description) { } // Free and unmap the handle from the SMMU - host1x.MemoryManager().Unmap(static_cast(handle_description.pin_virt_address), - handle_description.aligned_size); - host1x.Allocator().Free(handle_description.pin_virt_address, - static_cast(handle_description.aligned_size)); + auto& smmu = host1x.MemoryManager(); + smmu.Unmap(static_cast(handle_description.pin_virt_address), + handle_description.aligned_size); + smmu.Free(handle_description.pin_virt_address, + static_cast(handle_description.aligned_size)); handle_description.pin_virt_address = 0; } @@ -133,7 +132,32 @@ VAddr NvMap::GetHandleAddress(Handle::Id handle) { } } -u32 NvMap::PinHandle(NvMap::Handle::Id handle) { +NvResult NvMap::AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id) { + auto handle_description{GetHandle(handle)}; + if (!handle_description) [[unlikely]] { + return NvResult::BadParameter; + } + + if (handle_description->allocated) [[unlikely]] { + return NvResult::InsufficientMemory; + } + + std::scoped_lock lock(handle_description->mutex); + NvResult result = handle_description->Alloc(pFlags, pAlign, pKind, pAddress); + if (result != NvResult::Success) { + return result; + } + auto& smmu = host1x.MemoryManager(); + size_t total_size = static_cast(handle_description->aligned_size); + handle_description->d_address = smmu.Allocate(total_size); + if (handle_description->d_address == 0) { + return NvResult::InsufficientMemory; + } + smmu.Map(handle_description->d_address, handle_description->address, total_size, session_id); + return NvResult::Success; +} + +u32 NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id) { auto handle_description{GetHandle(handle)}; if (!handle_description) [[unlikely]] { return 0; @@ -157,11 +181,10 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) { } // If not then allocate some space and map it - u32 address{}; - auto& smmu_allocator = host1x.Allocator(); - auto& smmu_memory_manager = host1x.MemoryManager(); - while ((address = smmu_allocator.Allocate( - static_cast(handle_description->aligned_size))) == 0) { + DAddr address{}; + auto& smmu = host1x.MemoryManager(); + while ((address = smmu.AllocatePinned( + static_cast(handle_description->aligned_size))) == 0) { // Free handles until the allocation succeeds std::scoped_lock queueLock(unmap_queue_lock); if (auto freeHandleDesc{unmap_queue.front()}) { @@ -175,9 +198,9 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) { } } - smmu_memory_manager.Map(static_cast(address), handle_description->address, - handle_description->aligned_size); - handle_description->pin_virt_address = address; + smmu.Map(address, handle_description->address, handle_description->aligned_size, + session_id); + handle_description->pin_virt_address = static_cast(address); } handle_description->pins++; @@ -236,6 +259,11 @@ std::optional NvMap::FreeHandle(Handle::Id handle, bool interna std::scoped_lock queueLock(unmap_queue_lock); UnmapHandle(*handle_description); } + if (handle_description->allocated) { + auto& smmu = host1x.MemoryManager(); + smmu.Free(handle_description->d_address, handle_description->aligned_size); + smmu.Unmap(handle_description->d_address, handle_description->aligned_size); + } handle_description->pins = 0; } diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index a8e573890..7c3110d91 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -61,8 +61,10 @@ public: } flags{}; static_assert(sizeof(Flags) == sizeof(u32)); - u64 address{}; //!< The memory location in the guest's AS that this handle corresponds to, - //!< this can also be in the nvdrv tmem + VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, + //!< this can also be in the nvdrv tmem + DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, + //!< this can also be in the nvdrv tmem bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC //!< call @@ -125,7 +127,15 @@ public: * number of calls to `UnpinHandle` * @return The SMMU virtual address that the handle has been mapped to */ - u32 PinHandle(Handle::Id handle); + u32 PinHandle(Handle::Id handle, size_t session_id); + + /** + * @brief Maps a handle into the SMMU address space + * @note This operation is refcounted, the number of calls to this must eventually match the + * number of calls to `UnpinHandle` + * @return The SMMU virtual address that the handle has been mapped to + */ + NvResult AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id); /** * @brief When this has been called an equal number of times to `PinHandle` for the supplied diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index a04538d5d..ff91aabcb 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -62,7 +62,7 @@ public: * Called once a device is opened * @param fd The device fd */ - virtual void OnOpen(DeviceFD fd) = 0; + virtual void OnOpen(size_t session_id, DeviceFD fd) = 0; /** * Called once a device is closed diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 05a43d8dc..0ff41c6b2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -35,7 +35,7 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span in return NvResult::NotImplemented; } -void nvdisp_disp0::OnOpen(DeviceFD fd) {} +void nvdisp_disp0::OnOpen(size_t session_id, DeviceFD fd) {} void nvdisp_disp0::OnClose(DeviceFD fd) {} void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index daee05fe8..4e32ec191 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -32,7 +32,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; /// Performs a screen flip, drawing the buffer pointed to by the handle. 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 6b3639008..c92a7b2f6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -86,7 +86,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span i return NvResult::NotImplemented; } -void nvhost_as_gpu::OnOpen(DeviceFD fd) {} +void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { 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 79a21683d..0dd279f88 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -55,7 +55,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index b8dd34e24..c4033cf1b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -76,7 +76,7 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span inp return NvResult::NotImplemented; } -void nvhost_ctrl::OnOpen(DeviceFD fd) {} +void nvhost_ctrl::OnOpen(size_t session_id, DeviceFD fd) {} void nvhost_ctrl::OnClose(DeviceFD fd) {} diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 992124b60..84f419f16 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -32,7 +32,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 3e0c96456..75276c37c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span return NvResult::NotImplemented; } -void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} +void nvhost_ctrl_gpu::OnOpen(size_t session_id, DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index d170299bd..6147e37cc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -28,7 +28,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b0395c2f0..0929c7128 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -120,7 +120,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span inpu return NvResult::NotImplemented; } -void nvhost_gpu::OnOpen(DeviceFD fd) {} +void nvhost_gpu::OnOpen(size_t session_id, DeviceFD fd) {} void nvhost_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 88fd228ff..f5a396c40 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -47,7 +47,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f43914e1b..63228518e 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -35,7 +35,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span in case 0x7: return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output); case 0x9: - return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output); + return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output, fd); case 0xa: return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output); default: @@ -68,9 +68,10 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span in return NvResult::NotImplemented; } -void nvhost_nvdec::OnOpen(DeviceFD fd) { +void nvhost_nvdec::OnOpen(size_t session_id, DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream started"); system.SetNVDECActive(true); + sessions[fd] = session_id; } void nvhost_nvdec::OnClose(DeviceFD fd) { @@ -81,6 +82,10 @@ void nvhost_nvdec::OnClose(DeviceFD fd) { system.GPU().ClearCdmaInstance(iter->second); } system.SetNVDECActive(false); + auto it = sessions.find(fd); + if (it != sessions.end()) { + sessions.erase(it); + } } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index ad2233c49..1fb27b814 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -20,7 +20,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; }; 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 74c701b95..9ab0ae4d8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -133,10 +133,10 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) { return NvResult::Success; } -NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span entries) { +NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span entries, DeviceFD fd) { const size_t num_entries = std::min(params.num_entries, static_cast(entries.size())); for (size_t i = 0; i < num_entries; i++) { - entries[i].map_address = nvmap.PinHandle(entries[i].map_handle); + entries[i].map_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd]); } return NvResult::Success; 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 7ce748e18..b44b17a82 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -5,6 +5,8 @@ #include #include +#include + #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" @@ -111,7 +113,7 @@ protected: NvResult Submit(IoctlSubmit& params, std::span input, DeviceFD fd); NvResult GetSyncpoint(IoctlGetSyncpoint& params); NvResult GetWaitbase(IoctlGetWaitbase& params); - NvResult MapBuffer(IoctlMapBuffer& params, std::span entries); + NvResult MapBuffer(IoctlMapBuffer& params, std::span entries, DeviceFD fd); NvResult UnmapBuffer(IoctlMapBuffer& params, std::span entries); NvResult SetSubmitTimeout(u32 timeout); @@ -125,6 +127,7 @@ protected: NvCore::NvMap& nvmap; NvCore::ChannelType channel_type; std::array device_syncpoints{}; + std::unordered_map sessions; }; }; // namespace Devices } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 9e6b86458..1c88b39ab 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -44,7 +44,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span in return NvResult::NotImplemented; } -void nvhost_nvjpg::OnOpen(DeviceFD fd) {} +void nvhost_nvjpg::OnOpen(size_t session_id, DeviceFD fd) {} void nvhost_nvjpg::OnClose(DeviceFD fd) {} NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 790c97f6a..3e33dffef 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -22,7 +22,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; private: diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 87f8d7c22..d4c93ea5d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -33,7 +33,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span inpu case 0x3: return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output); case 0x9: - return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output); + return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output, fd); case 0xa: return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output); default: @@ -68,7 +68,9 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span inpu return NvResult::NotImplemented; } -void nvhost_vic::OnOpen(DeviceFD fd) {} +void nvhost_vic::OnOpen(size_t session_id, DeviceFD fd) { + sessions[fd] = session_id; +} void nvhost_vic::OnClose(DeviceFD fd) { auto& host1x_file = core.Host1xDeviceFile(); @@ -76,6 +78,10 @@ void nvhost_vic::OnClose(DeviceFD fd) { if (iter != host1x_file.fd_to_id.end()) { system.GPU().ClearCdmaInstance(iter->second); } + auto it = sessions.find(fd); + if (it != sessions.end()) { + sessions.erase(it); + } } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index cadbcb0a5..d70df0f20 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -19,7 +19,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 71b2e62ec..2b107f009 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -36,9 +36,9 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span input, case 0x3: return WrapFixed(this, &nvmap::IocFromId, input, output); case 0x4: - return WrapFixed(this, &nvmap::IocAlloc, input, output); + return WrapFixed(this, &nvmap::IocAlloc, input, output, fd); case 0x5: - return WrapFixed(this, &nvmap::IocFree, input, output); + return WrapFixed(this, &nvmap::IocFree, input, output, fd); case 0x9: return WrapFixed(this, &nvmap::IocParam, input, output); case 0xe: @@ -67,8 +67,15 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span input, st return NvResult::NotImplemented; } -void nvmap::OnOpen(DeviceFD fd) {} -void nvmap::OnClose(DeviceFD fd) {} +void nvmap::OnOpen(size_t session_id, DeviceFD fd) { + sessions[fd] = session_id; +} +void nvmap::OnClose(DeviceFD fd) { + auto it = sessions.find(fd); + if (it != sessions.end()) { + sessions.erase(it); + } +} NvResult nvmap::IocCreate(IocCreateParams& params) { LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); @@ -87,7 +94,7 @@ NvResult nvmap::IocCreate(IocCreateParams& params) { return NvResult::Success; } -NvResult nvmap::IocAlloc(IocAllocParams& params) { +NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); if (!params.handle) { @@ -116,15 +123,15 @@ NvResult nvmap::IocAlloc(IocAllocParams& params) { return NvResult::InsufficientMemory; } - const auto result = - handle_description->Alloc(params.flags, params.align, params.kind, params.address); + const auto result = file.AllocateHandle(params.handle, params.flags, params.align, params.kind, + params.address, sessions[fd]); if (result != NvResult::Success) { LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); return result; } bool is_out_io{}; - ASSERT(system.ApplicationProcess() - ->GetPageTable() + auto process = container.GetSession(sessions[fd])->process; + ASSERT(process->GetPageTable() .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, handle_description->size, Kernel::KMemoryPermission::None, true, false) @@ -224,7 +231,7 @@ NvResult nvmap::IocParam(IocParamParams& params) { return NvResult::Success; } -NvResult nvmap::IocFree(IocFreeParams& params) { +NvResult nvmap::IocFree(IocFreeParams& params, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called"); if (!params.handle) { @@ -233,9 +240,9 @@ NvResult nvmap::IocFree(IocFreeParams& params) { } if (auto freeInfo{file.FreeHandle(params.handle, false)}) { + auto process = container.GetSession(sessions[fd])->process; if (freeInfo->can_unlock) { - ASSERT(system.ApplicationProcess() - ->GetPageTable() + ASSERT(process->GetPageTable() .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) .IsSuccess()); } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 049c11028..ea5df2a9c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -33,7 +33,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(size_t session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; enum class HandleParameterType : u32_le { @@ -100,11 +100,11 @@ public: static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); NvResult IocCreate(IocCreateParams& params); - NvResult IocAlloc(IocAllocParams& params); + NvResult IocAlloc(IocAllocParams& params, DeviceFD fd); NvResult IocGetId(IocGetIdParams& params); NvResult IocFromId(IocFromIdParams& params); NvResult IocParam(IocParamParams& params); - NvResult IocFree(IocFreeParams& params); + NvResult IocFree(IocFreeParams& params, DeviceFD fd); private: /// Id to use for the next handle that is created. @@ -115,6 +115,7 @@ private: NvCore::Container& container; NvCore::NvMap& file; + std::unordered_map sessions; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9e46ee8dd..5191341db 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -45,13 +45,22 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) { void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { auto server_manager = std::make_unique(system); auto module = std::make_shared(system); - server_manager->RegisterNamedService("nvdrv", std::make_shared(system, module, "nvdrv")); - server_manager->RegisterNamedService("nvdrv:a", - std::make_shared(system, module, "nvdrv:a")); - server_manager->RegisterNamedService("nvdrv:s", - std::make_shared(system, module, "nvdrv:s")); - server_manager->RegisterNamedService("nvdrv:t", - std::make_shared(system, module, "nvdrv:t")); + const auto NvdrvInterfaceFactoryForApplication = [&, module] { + return std::make_shared(system, module, "nvdrv"); + }; + const auto NvdrvInterfaceFactoryForApplets = [&, module] { + return std::make_shared(system, module, "nvdrv:a"); + }; + const auto NvdrvInterfaceFactoryForSysmodules = [&, module] { + return std::make_shared(system, module, "nvdrv:a"); + }; + const auto NvdrvInterfaceFactory = [&, module] { + return std::make_shared(system, module, "nvdrv:t"); + }; + server_manager->RegisterNamedService("nvdrv", NvdrvInterfaceFactoryForApplication); + server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets); + server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules); + server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactory); server_manager->RegisterNamedService("nvmemp", std::make_shared(system)); nvnflinger.SetNVDrvInstance(module); ServerManager::RunServer(std::move(server_manager)); @@ -113,7 +122,7 @@ NvResult Module::VerifyFD(DeviceFD fd) const { return NvResult::Success; } -DeviceFD Module::Open(const std::string& device_name) { +DeviceFD Module::Open(const std::string& device_name, size_t session_id) { auto it = builders.find(device_name); if (it == builders.end()) { LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); @@ -124,7 +133,7 @@ DeviceFD Module::Open(const std::string& device_name) { auto& builder = it->second; auto device = builder(fd)->second; - device->OnOpen(fd); + device->OnOpen(session_id, fd); return fd; } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index d8622b3ca..d7648fb15 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -77,7 +77,7 @@ public: NvResult VerifyFD(DeviceFD fd) const; /// Opens a device node and returns a file descriptor to it. - DeviceFD Open(const std::string& device_name); + DeviceFD Open(const std::string& device_name, size_t session_id); /// Sends an ioctl command to the specified file descriptor. NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, std::span output); @@ -93,6 +93,10 @@ public: NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event); + NvCore::Container& GetContainer() { + return container; + } + private: friend class EventInterface; friend class Service::Nvnflinger::Nvnflinger; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index c8a880e84..492ad849a 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -3,14 +3,18 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "common/logging/log.h" +#include "common/scope_exit.h" #include "core/core.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvdrv_interface.h" +#pragma optimize("", off) + namespace Service::Nvidia { void NVDRV::Open(HLERequestContext& ctx) { @@ -37,7 +41,7 @@ void NVDRV::Open(HLERequestContext& ctx) { return; } - DeviceFD fd = nvdrv->Open(device_name); + DeviceFD fd = nvdrv->Open(device_name, session_id); rb.Push(fd); rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); @@ -150,12 +154,29 @@ void NVDRV::Close(HLERequestContext& ctx) { void NVDRV::Initialize(HLERequestContext& ctx) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + SCOPE_EXIT({ + rb.Push(ResultSuccess); + rb.PushEnum(NvResult::Success); + }); - is_initialized = true; + if (is_initialized) { + // No need to initialize again + return; + } - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(NvResult::Success); + IPC::RequestParser rp{ctx}; + const auto process_handle{ctx.GetCopyHandle(0)}; + // The transfer memory is lent to nvdrv as a work buffer since nvdrv is + // unable to allocate as much memory on its own. For HLE it's unnecessary to handle it + [[maybe_unused]] const auto transfer_memory_handle{ctx.GetCopyHandle(1)}; + [[maybe_unused]] const auto transfer_memory_size = rp.Pop(); + + auto& container = nvdrv->GetContainer(); + auto process = ctx.GetObjectFromHandle(process_handle); + session_id = container.OpenSession(process->DynamicCast()); + + is_initialized = true; } void NVDRV::QueryEvent(HLERequestContext& ctx) { @@ -242,6 +263,9 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr nvdrv_, const char* RegisterHandlers(functions); } -NVDRV::~NVDRV() = default; +NVDRV::~NVDRV() { + auto& container = nvdrv->GetContainer(); + container.CloseSession(session_id); +} } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index 6e98115dc..e7237c881 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h @@ -35,6 +35,7 @@ private: u64 pid{}; bool is_initialized{}; + size_t session_id{}; Common::ScratchBuffer output_buffer; Common::ScratchBuffer inline_output_buffer; }; diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 2fef6cc1a..d36eff4ec 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -87,19 +87,19 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, R_SUCCEED(); } -Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { +Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) { // Free the handle. Nvidia::Devices::nvmap::IocFreeParams free_params{ .handle = handle, }; - R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); + R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success, VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); } Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, - u32 size) { + u32 size, Nvidia::DeviceFD nvmap_fd) { // Assign the allocated memory to the handle. Nvidia::Devices::nvmap::IocAllocParams alloc_params{ .handle = handle, @@ -109,16 +109,15 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce .kind = 0, .address = GetInteger(buffer), }; - R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); + R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success, VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); } -Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, +Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd, Common::ProcessAddress buffer, u32 size) { // Get the nvmap device. - auto nvmap_fd = nvdrv.Open("/dev/nvmap"); auto nvmap = nvdrv.GetDevice(nvmap_fd); ASSERT(nvmap != nullptr); @@ -127,11 +126,11 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, // Ensure we maintain a clean state on failure. ON_RESULT_FAILURE { - ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle))); + ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd))); }; // Assign the allocated memory to the handle. - R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size)); + R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd)); } constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; @@ -197,8 +196,12 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u std::addressof(m_buffer_page_group), m_system, SharedBufferSize)); + auto& container = m_nvdrv->GetContainer(); + m_session_id = container.OpenSession(m_system.ApplicationProcess()); + m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id); + // Create an nvmap handle for the buffer and assign the memory to it. - R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address, + R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd, map_address, SharedBufferSize)); // Record the display id. diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h index c809c01b4..4b1a3d430 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h @@ -6,6 +6,7 @@ #include "common/math_util.h" #include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/ui/fence.h" +#include "core/hle/service/nvdrv/nvdata.h" namespace Kernel { class KPageGroup; @@ -53,13 +54,15 @@ private: u64 m_layer_id = 0; u32 m_buffer_nvmap_handle = 0; SharedMemoryPoolLayout m_pool_layout = {}; - + Nvidia::DeviceFD m_nvmap_fd = {}; + size_t m_session_id = {}; std::unique_ptr m_buffer_page_group; std::mutex m_guard; Core::System& m_system; Nvnflinger& m_flinger; std::shared_ptr m_nvdrv; + }; } // namespace Service::Nvnflinger diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 0469110e8..e4b38ae0b 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -126,7 +126,7 @@ void Nvnflinger::ShutdownLayers() { void Nvnflinger::SetNVDrvInstance(std::shared_ptr instance) { nvdrv = std::move(instance); - disp_fd = nvdrv->Open("/dev/nvdisp_disp0"); + disp_fd = nvdrv->Open("/dev/nvdisp_disp0", 0); } std::optional Nvnflinger::OpenDisplay(std::string_view name) { -- cgit v1.2.3 From c85d7ccd79fb69bc096cd19bb8f95ac9534ffc23 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 24 Dec 2023 21:49:54 +0100 Subject: SMMU: Implement backing CPU page protect/unprotect --- src/core/device_memory_manager.h | 51 +++++++++++++++++++++++- src/core/device_memory_manager.inc | 82 +++++++++++++++++++++++++++++++++++--- 2 files changed, 127 insertions(+), 6 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index 0861b792d..71b95016c 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -5,6 +5,8 @@ #include #include +#include +#include #include "common/common_types.h" #include "common/virtual_buffer.h" @@ -23,6 +25,7 @@ struct DeviceMemoryManagerAllocator; template class DeviceMemoryManager { using DeviceInterface = typename Traits::DeviceInterface; + using DeviceMethods = Traits::DeviceMethods; public: DeviceMemoryManager(const DeviceMemory& device_memory); @@ -35,7 +38,7 @@ public: DAddr AllocatePinned(size_t size); void Free(DAddr start, size_t size); - void Map(DAddr address, VAddr virtual_address, size_t size, size_t p_id); + void Map(DAddr address, VAddr virtual_address, size_t size, size_t process_id); void Unmap(DAddr address, size_t size); // Write / Read @@ -57,6 +60,8 @@ public: size_t RegisterProcess(Memory::Memory* memory); void UnregisterProcess(size_t id); + void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta); + private: static constexpr bool supports_pinning = Traits::supports_pinning; static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; @@ -90,8 +95,52 @@ private: Common::VirtualBuffer compressed_physical_ptr; Common::VirtualBuffer compressed_device_addr; + // Process memory interfaces + std::deque id_pool; std::deque registered_processes; + + // Memory protection management + + static constexpr size_t guest_max_as_bits = 39; + static constexpr size_t guest_as_size = 1ULL << guest_max_as_bits; + static constexpr size_t guest_mask = guest_as_size - 1ULL; + static constexpr size_t process_id_start_bit = guest_max_as_bits; + + std::pair ExtractCPUBacking(size_t page_index) { + auto content = cpu_backing_address[page_index]; + const VAddr address = content & guest_mask; + const size_t process_id = static_cast(content >> process_id_start_bit); + return std::make_pair(process_id, address); + } + + void InsertCPUBacking(size_t page_index, VAddr address, size_t process_id) { + cpu_backing_address[page_index] = address | (process_id << page_index); + } + + Common::VirtualBuffer cpu_backing_address; + static constexpr size_t subentries = 4; + static constexpr size_t subentries_mask = subentries - 1; + class CounterEntry final { + public: + CounterEntry() = default; + + std::atomic_uint16_t& Count(std::size_t page) { + return values[page & subentries_mask]; + } + + const std::atomic_uint16_t& Count(std::size_t page) const { + return values[page & subentries_mask]; + } + + private: + std::array values{}; + }; + static_assert(sizeof(CounterEntry) == subentries * sizeof(u16), "CounterEntry should be 8 bytes!"); + + static constexpr size_t num_counter_entries = (1ULL << (device_virtual_bits - page_bits)) / subentries; + using CachedPages = std::array; + std::unique_ptr cached_pages; }; } // namespace Core \ No newline at end of file diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 1f52b92d5..77410f72f 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -2,12 +2,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include #include "common/address_space.h" #include "common/address_space.inc" #include "common/alignment.h" +#include "common/assert.h" +#include "common/div_ceil.h" #include "common/scope_exit.h" #include "core/device_memory.h" #include "core/device_memory_manager.h" @@ -51,7 +54,11 @@ struct DeviceMemoryManagerAllocator { } DAddr AllocatePinned(size_t size) { - return pin_allocator.Allocate(size); + if constexpr (supports_pinning) { + return pin_allocator.Allocate(size); + } else { + return DAddr{}; + } } void DoInRange(DAddr address, size_t size, auto pin_func, auto main_func) { @@ -100,6 +107,7 @@ DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memo interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)) { impl = std::make_unique>(); + cached_pages = std::make_unique(); } template @@ -132,14 +140,14 @@ void DeviceMemoryManager::Free(DAddr start, size_t size) { template void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size_t size, - size_t p_id) { - Core::Memory::Memory* process_memory = registered_processes[p_id]; + size_t process_id) { + Core::Memory::Memory* process_memory = registered_processes[process_id]; size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; std::atomic_thread_fence(std::memory_order_acquire); for (size_t i = 0; i < num_pages; i++) { - auto* ptr = process_memory->GetPointer( - Common::ProcessAddress(virtual_address + i * Memory::YUZU_PAGESIZE)); + const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE; + auto* ptr = process_memory->GetPointer(Common::ProcessAddress(new_vaddress)); if (ptr == nullptr) [[unlikely]] { compressed_physical_ptr[start_page_d + i] = 0; continue; @@ -147,6 +155,7 @@ void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size auto phys_addr = static_cast(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U; compressed_physical_ptr[start_page_d + i] = phys_addr; compressed_device_addr[phys_addr - 1U] = static_cast(start_page_d + i); + InsertCPUBacking(start_page_d + i, new_vaddress, process_id); } std::atomic_thread_fence(std::memory_order_release); } @@ -159,6 +168,7 @@ void DeviceMemoryManager::Unmap(DAddr address, size_t size) { for (size_t i = 0; i < num_pages; i++) { auto phys_addr = compressed_physical_ptr[start_page_d + i]; compressed_physical_ptr[start_page_d + i] = 0; + cpu_backing_address[start_page_d + i] = 0; if (phys_addr != 0) { compressed_device_addr[phys_addr - 1] = 0; } @@ -301,4 +311,66 @@ void DeviceMemoryManager::UnregisterProcess(size_t id) { id_pool.push_front(id); } +template +void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { + u64 uncache_begin = 0; + u64 cache_begin = 0; + u64 uncache_bytes = 0; + u64 cache_bytes = 0; + const auto* MarkRegionCaching = &DeviceMemoryManager::DeviceMethods::MarkRegionCaching; + + std::atomic_thread_fence(std::memory_order_acquire); + const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); + size_t page = addr >> Memory::YUZU_PAGEBITS; + auto [process_id, base_vaddress] = ExtractCPUBacking(page); + size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS; + auto* memory_interface = registered_processes[process_id]; + for (; page != page_end; ++page) { + std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page); + + if (delta > 0) { + ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits::max(), + "Count may overflow!"); + } else if (delta < 0) { + ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); + } else { + ASSERT_MSG(false, "Delta must be non-zero!"); + } + + // Adds or subtracts 1, as count is a unsigned 8-bit value + count.fetch_add(static_cast(delta), std::memory_order_release); + + // Assume delta is either -1 or 1 + if (count.load(std::memory_order::relaxed) == 0) { + if (uncache_bytes == 0) { + uncache_begin = vpage; + } + uncache_bytes += Memory::YUZU_PAGESIZE; + } else if (uncache_bytes > 0) { + MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, + uncache_bytes, false); + uncache_bytes = 0; + } + if (count.load(std::memory_order::relaxed) == 1 && delta > 0) { + if (cache_bytes == 0) { + cache_begin = vpage; + } + cache_bytes += Memory::YUZU_PAGESIZE; + } else if (cache_bytes > 0) { + MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, + true); + cache_bytes = 0; + } + vpage++; + } + if (uncache_bytes > 0) { + MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, + false); + } + if (cache_bytes > 0) { + MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, + true); + } +} + } // namespace Core \ No newline at end of file -- cgit v1.2.3 From 0a2536a0df1f4aea406f2132d3edda0430acc9d1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 25 Dec 2023 07:32:16 +0100 Subject: SMMU: Initial adaptation to video_core. --- src/core/CMakeLists.txt | 2 + src/core/core.cpp | 2 +- src/core/core.h | 2 +- src/core/device_memory_manager.h | 43 +++- src/core/device_memory_manager.inc | 72 ++++++- src/core/gpu_dirty_memory_manager.h | 10 +- src/core/guest_memory.h | 218 +++++++++++++++++++++ src/core/hle/service/hle_ipc.cpp | 61 ++---- src/core/hle/service/hle_ipc.h | 9 +- src/core/hle/service/nvdrv/core/nvmap.cpp | 64 ++---- src/core/hle/service/nvdrv/core/nvmap.h | 19 +- .../hle/service/nvdrv/devices/nvdisp_disp0.cpp | 2 +- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 57 +++--- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 20 +- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 8 +- src/core/hle/service/nvdrv/devices/nvmap.cpp | 4 +- src/core/hle/service/nvdrv/nvdrv_interface.cpp | 6 +- src/core/memory.cpp | 25 ++- src/core/memory.h | 205 ------------------- 19 files changed, 441 insertions(+), 388 deletions(-) create mode 100644 src/core/guest_memory.h (limited to 'src/core') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 293d9647b..ca54eb6c6 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -37,6 +37,8 @@ add_library(core STATIC debugger/gdbstub_arch.h debugger/gdbstub.cpp debugger/gdbstub.h + device_memory_manager.h + device_memory_manager.inc device_memory.cpp device_memory.h file_sys/fssystem/fs_i_storage.h diff --git a/src/core/core.cpp b/src/core/core.cpp index 461eea9c8..04e1f13ff 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -651,7 +651,7 @@ size_t System::GetCurrentHostThreadID() const { return impl->kernel.GetCurrentHostThreadID(); } -void System::GatherGPUDirtyMemory(std::function& callback) { +void System::GatherGPUDirtyMemory(std::function& callback) { return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); } diff --git a/src/core/core.h b/src/core/core.h index ba5add0dc..20ec2ffff 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -224,7 +224,7 @@ public: /// Prepare the core emulation for a reschedule void PrepareReschedule(u32 core_index); - void GatherGPUDirtyMemory(std::function& callback); + void GatherGPUDirtyMemory(std::function& callback); [[nodiscard]] size_t GetCurrentHostThreadID() const; diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index 71b95016c..1a63cbd09 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -3,10 +3,11 @@ #pragma once -#include -#include #include #include +#include +#include +#include #include "common/common_types.h" #include "common/virtual_buffer.h" @@ -48,26 +49,54 @@ public: template const T* GetPointer(DAddr address) const; + DAddr GetAddressFromPAddr(PAddr address) const { + DAddr subbits = static_cast(address & page_mask); + return (static_cast(compressed_device_addr[(address >> page_bits)]) << page_bits) + subbits; + } + + PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const { + PAddr subbits = static_cast(address & page_mask); + auto paddr = compressed_physical_ptr[(address >> page_bits)]; + if (paddr == 0) { + return 0; + } + return (static_cast(paddr - 1) << page_bits) + subbits; + } + template void Write(DAddr address, T value); template T Read(DAddr address) const; + const u8* GetSpan(const DAddr src_addr, const std::size_t size) const { + return nullptr; + } + + u8* GetSpan(const DAddr src_addr, const std::size_t size) { + return nullptr; + } + void ReadBlock(DAddr address, void* dest_pointer, size_t size); - void WriteBlock(DAddr address, void* src_pointer, size_t size); + void ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size); + void WriteBlock(DAddr address, const void* src_pointer, size_t size); + void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size); size_t RegisterProcess(Memory::Memory* memory); void UnregisterProcess(size_t id); void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta); + static constexpr size_t AS_BITS = Traits::device_virtual_bits; + private: static constexpr bool supports_pinning = Traits::supports_pinning; static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; static constexpr size_t device_as_size = 1ULL << device_virtual_bits; static constexpr size_t physical_max_bits = 33; static constexpr size_t page_bits = 12; + static constexpr size_t page_size = 1ULL << page_bits; + static constexpr size_t page_mask = page_size - 1ULL; static constexpr u32 physical_address_base = 1U << page_bits; template @@ -136,11 +165,15 @@ private: private: std::array values{}; }; - static_assert(sizeof(CounterEntry) == subentries * sizeof(u16), "CounterEntry should be 8 bytes!"); + static_assert(sizeof(CounterEntry) == subentries * sizeof(u16), + "CounterEntry should be 8 bytes!"); - static constexpr size_t num_counter_entries = (1ULL << (device_virtual_bits - page_bits)) / subentries; + static constexpr size_t num_counter_entries = + (1ULL << (device_virtual_bits - page_bits)) / subentries; using CachedPages = std::array; std::unique_ptr cached_pages; + std::mutex counter_guard; + std::mutex mapping_guard; }; } // namespace Core \ No newline at end of file diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 77410f72f..8c5f82d31 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -105,7 +105,8 @@ template DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memory_) : physical_base{reinterpret_cast(device_memory_.buffer.BackingBasePointer())}, interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), - compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)) { + compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)), + cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) { impl = std::make_unique>(); cached_pages = std::make_unique(); } @@ -144,10 +145,10 @@ void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size Core::Memory::Memory* process_memory = registered_processes[process_id]; size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; - std::atomic_thread_fence(std::memory_order_acquire); + std::scoped_lock lk(mapping_guard); for (size_t i = 0; i < num_pages; i++) { const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE; - auto* ptr = process_memory->GetPointer(Common::ProcessAddress(new_vaddress)); + auto* ptr = process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress)); if (ptr == nullptr) [[unlikely]] { compressed_physical_ptr[start_page_d + i] = 0; continue; @@ -157,14 +158,14 @@ void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size compressed_device_addr[phys_addr - 1U] = static_cast(start_page_d + i); InsertCPUBacking(start_page_d + i, new_vaddress, process_id); } - std::atomic_thread_fence(std::memory_order_release); } template void DeviceMemoryManager::Unmap(DAddr address, size_t size) { size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; - std::atomic_thread_fence(std::memory_order_acquire); + interface->InvalidateRegion(address, size); + std::scoped_lock lk(mapping_guard); for (size_t i = 0; i < num_pages; i++) { auto phys_addr = compressed_physical_ptr[start_page_d + i]; compressed_physical_ptr[start_page_d + i] = 0; @@ -173,7 +174,6 @@ void DeviceMemoryManager::Unmap(DAddr address, size_t size) { compressed_device_addr[phys_addr - 1] = 0; } } - std::atomic_thread_fence(std::memory_order_release); } template @@ -256,6 +256,45 @@ void DeviceMemoryManager::WalkBlock(DAddr addr, std::size_t size, auto o template void DeviceMemoryManager::ReadBlock(DAddr address, void* dest_pointer, size_t size) { + interface->FlushRegion(address, size); + WalkBlock( + address, size, + [&](size_t copy_amount, DAddr current_vaddr) { + LOG_ERROR( + HW_Memory, + "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, address, size); + std::memset(dest_pointer, 0, copy_amount); + }, + [&](size_t copy_amount, const u8* const src_ptr) { + std::memcpy(dest_pointer, src_ptr, copy_amount); + }, + [&](const std::size_t copy_amount) { + dest_pointer = static_cast(dest_pointer) + copy_amount; + }); +} + +template +void DeviceMemoryManager::WriteBlock(DAddr address, const void* src_pointer, size_t size) { + WalkBlock( + address, size, + [&](size_t copy_amount, DAddr current_vaddr) { + LOG_ERROR( + HW_Memory, + "Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, address, size); + }, + [&](size_t copy_amount, u8* const dst_ptr) { + std::memcpy(dst_ptr, src_pointer, copy_amount); + }, + [&](const std::size_t copy_amount) { + src_pointer = static_cast(src_pointer) + copy_amount; + }); + interface->InvalidateRegion(address, size); +} + +template +void DeviceMemoryManager::ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size) { WalkBlock( address, size, [&](size_t copy_amount, DAddr current_vaddr) { @@ -274,7 +313,8 @@ void DeviceMemoryManager::ReadBlock(DAddr address, void* dest_pointer, s } template -void DeviceMemoryManager::WriteBlock(DAddr address, void* src_pointer, size_t size) { +void DeviceMemoryManager::WriteBlockUnsafe(DAddr address, const void* src_pointer, + size_t size) { WalkBlock( address, size, [&](size_t copy_amount, DAddr current_vaddr) { @@ -287,7 +327,7 @@ void DeviceMemoryManager::WriteBlock(DAddr address, void* src_pointer, s std::memcpy(dst_ptr, src_pointer, copy_amount); }, [&](const std::size_t copy_amount) { - src_pointer = static_cast(src_pointer) + copy_amount; + src_pointer = static_cast(src_pointer) + copy_amount; }); } @@ -313,6 +353,18 @@ void DeviceMemoryManager::UnregisterProcess(size_t id) { template void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { + bool locked = false; + auto lock = [&] { + if (!locked) { + counter_guard.lock(); + locked = true; + } + }; + SCOPE_EXIT({ + if (locked) { + counter_guard.unlock(); + } + }); u64 uncache_begin = 0; u64 cache_begin = 0; u64 uncache_bytes = 0; @@ -347,6 +399,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size } uncache_bytes += Memory::YUZU_PAGESIZE; } else if (uncache_bytes > 0) { + lock(); MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); uncache_bytes = 0; @@ -357,6 +410,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size } cache_bytes += Memory::YUZU_PAGESIZE; } else if (cache_bytes > 0) { + lock(); MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, true); cache_bytes = 0; @@ -364,10 +418,12 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size vpage++; } if (uncache_bytes > 0) { + lock(); MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); } if (cache_bytes > 0) { + lock(); MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, true); } diff --git a/src/core/gpu_dirty_memory_manager.h b/src/core/gpu_dirty_memory_manager.h index 9687531e8..f1abf4f83 100644 --- a/src/core/gpu_dirty_memory_manager.h +++ b/src/core/gpu_dirty_memory_manager.h @@ -23,7 +23,7 @@ public: ~GPUDirtyMemoryManager() = default; - void Collect(VAddr address, size_t size) { + void Collect(PAddr address, size_t size) { TransformAddress t = BuildTransform(address, size); TransformAddress tmp, original; do { @@ -47,7 +47,7 @@ public: std::memory_order_relaxed)); } - void Gather(std::function& callback) { + void Gather(std::function& callback) { { std::scoped_lock lk(guard); TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed); @@ -65,7 +65,7 @@ public: mask = mask >> empty_bits; const size_t continuous_bits = std::countr_one(mask); - callback((static_cast(transform.address) << page_bits) + offset, + callback((static_cast(transform.address) << page_bits) + offset, continuous_bits << align_bits); mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0; offset += continuous_bits << align_bits; @@ -89,7 +89,7 @@ private: constexpr static size_t align_mask = align_size - 1; constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U}; - bool IsValid(VAddr address) { + bool IsValid(PAddr address) { return address < (1ULL << 39); } @@ -103,7 +103,7 @@ private: return mask; } - TransformAddress BuildTransform(VAddr address, size_t size) { + TransformAddress BuildTransform(PAddr address, size_t size) { const size_t minor_address = address & page_mask; const size_t minor_bit = minor_address >> align_bits; const size_t top_bit = (minor_address + size + align_mask) >> align_bits; diff --git a/src/core/guest_memory.h b/src/core/guest_memory.h new file mode 100644 index 000000000..0b349cc17 --- /dev/null +++ b/src/core/guest_memory.h @@ -0,0 +1,218 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include + +#include "common/scratch_buffer.h" +#include "core/memory.h" + +namespace Core::Memory { + +enum GuestMemoryFlags : u32 { + Read = 1 << 0, + Write = 1 << 1, + Safe = 1 << 2, + Cached = 1 << 3, + + SafeRead = Read | Safe, + SafeWrite = Write | Safe, + SafeReadWrite = SafeRead | SafeWrite, + SafeReadCachedWrite = SafeReadWrite | Cached, + + UnsafeRead = Read, + UnsafeWrite = Write, + UnsafeReadWrite = UnsafeRead | UnsafeWrite, + UnsafeReadCachedWrite = UnsafeReadWrite | Cached, +}; + +namespace { +template +class GuestMemory { + using iterator = T*; + using const_iterator = const T*; + using value_type = T; + using element_type = T; + using iterator_category = std::contiguous_iterator_tag; + +public: + GuestMemory() = delete; + explicit GuestMemory(M& memory, u64 addr, std::size_t size, + Common::ScratchBuffer* backup = nullptr) + : m_memory{memory}, m_addr{addr}, m_size{size} { + static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write); + if constexpr (FLAGS & GuestMemoryFlags::Read) { + Read(addr, size, backup); + } + } + + ~GuestMemory() = default; + + T* data() noexcept { + return m_data_span.data(); + } + + const T* data() const noexcept { + return m_data_span.data(); + } + + size_t size() const noexcept { + return m_size; + } + + size_t size_bytes() const noexcept { + return this->size() * sizeof(T); + } + + [[nodiscard]] T* begin() noexcept { + return this->data(); + } + + [[nodiscard]] const T* begin() const noexcept { + return this->data(); + } + + [[nodiscard]] T* end() noexcept { + return this->data() + this->size(); + } + + [[nodiscard]] const T* end() const noexcept { + return this->data() + this->size(); + } + + T& operator[](size_t index) noexcept { + return m_data_span[index]; + } + + const T& operator[](size_t index) const noexcept { + return m_data_span[index]; + } + + void SetAddressAndSize(u64 addr, std::size_t size) noexcept { + m_addr = addr; + m_size = size; + m_addr_changed = true; + } + + std::span Read(u64 addr, std::size_t size, + Common::ScratchBuffer* backup = nullptr) noexcept { + m_addr = addr; + m_size = size; + if (m_size == 0) { + m_is_data_copy = true; + return {}; + } + + if (this->TrySetSpan()) { + if constexpr (FLAGS & GuestMemoryFlags::Safe) { + m_memory.FlushRegion(m_addr, this->size_bytes()); + } + } else { + if (backup) { + backup->resize_destructive(this->size()); + m_data_span = *backup; + } else { + m_data_copy.resize(this->size()); + m_data_span = std::span(m_data_copy); + } + m_is_data_copy = true; + m_span_valid = true; + if constexpr (FLAGS & GuestMemoryFlags::Safe) { + m_memory.ReadBlock(m_addr, this->data(), this->size_bytes()); + } else { + m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes()); + } + } + return m_data_span; + } + + void Write(std::span write_data) noexcept { + if constexpr (FLAGS & GuestMemoryFlags::Cached) { + m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes()); + } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { + m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes()); + } else { + m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes()); + } + } + + bool TrySetSpan() noexcept { + if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) { + m_data_span = {reinterpret_cast(ptr), this->size()}; + m_span_valid = true; + return true; + } + return false; + } + +protected: + bool IsDataCopy() const noexcept { + return m_is_data_copy; + } + + bool AddressChanged() const noexcept { + return m_addr_changed; + } + + M& m_memory; + u64 m_addr{}; + size_t m_size{}; + std::span m_data_span{}; + std::vector m_data_copy{}; + bool m_span_valid{false}; + bool m_is_data_copy{false}; + bool m_addr_changed{false}; +}; + +template +class GuestMemoryScoped : public GuestMemory { +public: + GuestMemoryScoped() = delete; + explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size, + Common::ScratchBuffer* backup = nullptr) + : GuestMemory(memory, addr, size, backup) { + if constexpr (!(FLAGS & GuestMemoryFlags::Read)) { + if (!this->TrySetSpan()) { + if (backup) { + this->m_data_span = *backup; + this->m_span_valid = true; + this->m_is_data_copy = true; + } + } + } + } + + ~GuestMemoryScoped() { + if constexpr (FLAGS & GuestMemoryFlags::Write) { + if (this->size() == 0) [[unlikely]] { + return; + } + + if (this->AddressChanged() || this->IsDataCopy()) { + ASSERT(this->m_span_valid); + if constexpr (FLAGS & GuestMemoryFlags::Cached) { + this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes()); + } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { + this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes()); + } else { + this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes()); + } + } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || (FLAGS & GuestMemoryFlags::Cached)) { + this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes()); + } + } + } +}; +} // namespace + +template +using CpuGuestMemory = GuestMemory; +template +using CpuGuestMemoryScoped = GuestMemoryScoped; + +} // namespace Tegra::Memory diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 3f38ceb03..9f6274c7d 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -22,19 +22,7 @@ #include "core/hle/service/hle_ipc.h" #include "core/hle/service/ipc_helpers.h" #include "core/memory.h" - -namespace { -static thread_local std::array read_buffer_data_a{ - Common::ScratchBuffer(), - Common::ScratchBuffer(), - Common::ScratchBuffer(), -}; -static thread_local std::array read_buffer_data_x{ - Common::ScratchBuffer(), - Common::ScratchBuffer(), - Common::ScratchBuffer(), -}; -} // Anonymous namespace +#include "core/guest_memory.h" namespace Service { @@ -343,48 +331,27 @@ std::vector HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons } std::span HLERequestContext::ReadBufferA(std::size_t buffer_index) const { - static thread_local std::array read_buffer_a{ - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - }; + Core::Memory::CpuGuestMemory gm(memory, 0, 0); ASSERT_OR_EXECUTE_MSG( BufferDescriptorA().size() > buffer_index, { return {}; }, "BufferDescriptorA invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_a[buffer_index]; - return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), - BufferDescriptorA()[buffer_index].Size(), - &read_buffer_data_a[buffer_index]); + return gm.Read(BufferDescriptorA()[buffer_index].Address(), + BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]); } std::span HLERequestContext::ReadBufferX(std::size_t buffer_index) const { - static thread_local std::array read_buffer_x{ - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - }; + Core::Memory::CpuGuestMemory gm(memory, 0, 0); ASSERT_OR_EXECUTE_MSG( BufferDescriptorX().size() > buffer_index, { return {}; }, "BufferDescriptorX invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_x[buffer_index]; - return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), - BufferDescriptorX()[buffer_index].Size(), - &read_buffer_data_x[buffer_index]); + return gm.Read(BufferDescriptorX()[buffer_index].Address(), + BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]); } std::span HLERequestContext::ReadBuffer(std::size_t buffer_index) const { - static thread_local std::array read_buffer_a{ - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - }; - static thread_local std::array read_buffer_x{ - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - Core::Memory::CpuGuestMemory(memory, 0, 0), - }; + Core::Memory::CpuGuestMemory gm(memory, 0, 0); const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && BufferDescriptorA()[buffer_index].Size()}; @@ -401,18 +368,14 @@ std::span HLERequestContext::ReadBuffer(std::size_t buffer_index) cons ASSERT_OR_EXECUTE_MSG( BufferDescriptorA().size() > buffer_index, { return {}; }, "BufferDescriptorA invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_a[buffer_index]; - return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), - BufferDescriptorA()[buffer_index].Size(), - &read_buffer_data_a[buffer_index]); + return gm.Read(BufferDescriptorA()[buffer_index].Address(), + BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]); } else { ASSERT_OR_EXECUTE_MSG( BufferDescriptorX().size() > buffer_index, { return {}; }, "BufferDescriptorX invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_x[buffer_index]; - return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), - BufferDescriptorX()[buffer_index].Size(), - &read_buffer_data_x[buffer_index]); + return gm.Read(BufferDescriptorX()[buffer_index].Address(), + BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]); } } diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index d550a11b7..8329d7265 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h @@ -19,8 +19,6 @@ #include "core/hle/ipc.h" #include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/svc_common.h" -#include "core/hle/kernel/k_auto_object.h" -#include "core/hle/kernel/k_handle_table.h" union Result; @@ -377,10 +375,6 @@ public: return nullptr; } - Kernel::KScopedAutoObject GetObjectFromHandle(u32 handle) { - return GetClientHandleTable().GetObjectForIpc(handle, thread); - } - [[nodiscard]] std::shared_ptr GetManager() const { return manager.lock(); } @@ -432,6 +426,9 @@ private: Kernel::KernelCore& kernel; Core::Memory::Memory& memory; + + mutable std::array, 3> read_buffer_data_a{}; + mutable std::array, 3> read_buffer_data_x{}; }; } // namespace Service diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index fd6c9aa0c..7879c6f04 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -2,6 +2,8 @@ // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors // SPDX-License-Identifier: GPL-3.0-or-later +#include + #include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" @@ -18,6 +20,7 @@ NvMap::Handle::Handle(u64 size_, Id id_) } NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { + std::scoped_lock lock(mutex); // Handles cannot be allocated twice if (allocated) { return NvResult::AccessDenied; @@ -78,11 +81,9 @@ void NvMap::UnmapHandle(Handle& handle_description) { // Free and unmap the handle from the SMMU auto& smmu = host1x.MemoryManager(); - smmu.Unmap(static_cast(handle_description.pin_virt_address), - handle_description.aligned_size); - smmu.Free(handle_description.pin_virt_address, - static_cast(handle_description.aligned_size)); - handle_description.pin_virt_address = 0; + smmu.Unmap(handle_description.d_address, handle_description.aligned_size); + smmu.Free(handle_description.d_address, static_cast(handle_description.aligned_size)); + handle_description.d_address = 0; } bool NvMap::TryRemoveHandle(const Handle& handle_description) { @@ -123,41 +124,16 @@ std::shared_ptr NvMap::GetHandle(Handle::Id handle) { } } -VAddr NvMap::GetHandleAddress(Handle::Id handle) { +DAddr NvMap::GetHandleAddress(Handle::Id handle) { std::scoped_lock lock(handles_lock); try { - return handles.at(handle)->address; + return handles.at(handle)->d_address; } catch (std::out_of_range&) { return 0; } } -NvResult NvMap::AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id) { - auto handle_description{GetHandle(handle)}; - if (!handle_description) [[unlikely]] { - return NvResult::BadParameter; - } - - if (handle_description->allocated) [[unlikely]] { - return NvResult::InsufficientMemory; - } - - std::scoped_lock lock(handle_description->mutex); - NvResult result = handle_description->Alloc(pFlags, pAlign, pKind, pAddress); - if (result != NvResult::Success) { - return result; - } - auto& smmu = host1x.MemoryManager(); - size_t total_size = static_cast(handle_description->aligned_size); - handle_description->d_address = smmu.Allocate(total_size); - if (handle_description->d_address == 0) { - return NvResult::InsufficientMemory; - } - smmu.Map(handle_description->d_address, handle_description->address, total_size, session_id); - return NvResult::Success; -} - -u32 NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id) { +DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_area_pin) { auto handle_description{GetHandle(handle)}; if (!handle_description) [[unlikely]] { return 0; @@ -176,35 +152,38 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id) { handle_description->unmap_queue_entry.reset(); handle_description->pins++; - return handle_description->pin_virt_address; + return handle_description->d_address; } } + using namespace std::placeholders; // If not then allocate some space and map it DAddr address{}; auto& smmu = host1x.MemoryManager(); - while ((address = smmu.AllocatePinned( - static_cast(handle_description->aligned_size))) == 0) { + auto allocate = std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); + //: std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); + while ((address = allocate(static_cast(handle_description->aligned_size))) == 0) { // 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 (handle_description->pin_virt_address) + if (handle_description->d_address) UnmapHandle(*freeHandleDesc); } else { LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); } } + handle_description->d_address = address; + smmu.Map(address, handle_description->address, handle_description->aligned_size, session_id); - handle_description->pin_virt_address = static_cast(address); } handle_description->pins++; - return handle_description->pin_virt_address; + return handle_description->d_address; } void NvMap::UnpinHandle(Handle::Id handle) { @@ -255,15 +234,10 @@ std::optional NvMap::FreeHandle(Handle::Id handle, bool interna LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); } else if (handle_description->dupes == 0) { // Force unmap the handle - if (handle_description->pin_virt_address) { + if (handle_description->d_address) { std::scoped_lock queueLock(unmap_queue_lock); UnmapHandle(*handle_description); } - if (handle_description->allocated) { - auto& smmu = host1x.MemoryManager(); - smmu.Free(handle_description->d_address, handle_description->aligned_size); - smmu.Unmap(handle_description->d_address, handle_description->aligned_size); - } handle_description->pins = 0; } diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 7c3110d91..e9e9e8b5b 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -48,7 +48,7 @@ public: using Id = u32; Id id; //!< A globally unique identifier for this handle - s32 pins{}; + s64 pins{}; u32 pin_virt_address{}; std::optional>::iterator> unmap_queue_entry{}; @@ -63,15 +63,14 @@ public: VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, //!< this can also be in the nvdrv tmem - DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, - //!< this can also be in the nvdrv tmem bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC //!< call 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. + DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, + //!< this can also be in the nvdrv tmem Handle(u64 size, Id id); @@ -119,15 +118,7 @@ public: std::shared_ptr 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 - * number of calls to `UnpinHandle` - * @return The SMMU virtual address that the handle has been mapped to - */ - u32 PinHandle(Handle::Id handle, size_t session_id); + DAddr GetHandleAddress(Handle::Id handle); /** * @brief Maps a handle into the SMMU address space @@ -135,7 +126,7 @@ public: * number of calls to `UnpinHandle` * @return The SMMU virtual address that the handle has been mapped to */ - NvResult AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id); + DAddr PinHandle(Handle::Id handle, size_t session_id, bool low_area_pin); /** * @brief When this has been called an equal number of times to `PinHandle` for the supplied diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 0ff41c6b2..f1404b9da 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -42,7 +42,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form u32 height, u32 stride, android::BufferTransformFlags transform, const Common::Rectangle& crop_rect, std::array& fences, u32 num_fences) { - const VAddr addr = nvmap.GetHandleAddress(buffer_handle); + const DAddr addr = nvmap.GetHandleAddress(buffer_handle); LOG_TRACE(Service, "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", addr, offset, width, height, stride, format); 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 c92a7b2f6..8bc10eac2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -40,15 +40,15 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span i case 0x3: return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output); case 0x5: - return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output); + return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output, fd); case 0x6: - return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output); + return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output, fd); case 0x8: return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output); case 0x9: return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output); case 0x14: - return WrapVariable(this, &nvhost_as_gpu::Remap, input, output); + return WrapVariable(this, &nvhost_as_gpu::Remap, input, output, fd); default: break; } @@ -86,8 +86,15 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span i return NvResult::NotImplemented; } -void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {} -void nvhost_as_gpu::OnClose(DeviceFD fd) {} +void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) { + sessions[fd] = session_id; +} +void nvhost_as_gpu::OnClose(DeviceFD fd) { + auto it = sessions.find(fd); + if (it != sessions.end()) { + sessions.erase(it); + } +} NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); @@ -206,6 +213,8 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { static_cast(aligned_size >> page_size_bits)); } + nvmap.UnpinHandle(mapping->handle); + // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state // Only FreeSpace can unmap them fully if (mapping->sparse_alloc) { @@ -259,7 +268,7 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) { return NvResult::Success; } -NvResult nvhost_as_gpu::Remap(std::span entries) { +NvResult nvhost_as_gpu::Remap(std::span entries, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size()); if (!vm.initialised) { @@ -293,19 +302,19 @@ NvResult nvhost_as_gpu::Remap(std::span entries) { return NvResult::BadValue; } - VAddr cpu_address{static_cast( - handle->address + - (static_cast(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; + DAddr base = nvmap.PinHandle(entry.handle, sessions[fd], false); + DAddr device_address{static_cast( + base + (static_cast(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; - gmmu->Map(virtual_address, cpu_address, size, static_cast(entry.kind), - use_big_pages); + gmmu->Map(virtual_address, device_address, size, + static_cast(entry.kind), use_big_pages); } } return NvResult::Success; } -NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { +NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" ", offset={}", @@ -331,9 +340,9 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { } u64 gpu_address{static_cast(params.offset + params.buffer_offset)}; - VAddr cpu_address{mapping->ptr + params.buffer_offset}; + VAddr device_address{mapping->ptr + params.buffer_offset}; - gmmu->Map(gpu_address, cpu_address, params.mapping_size, + gmmu->Map(gpu_address, device_address, params.mapping_size, static_cast(params.kind), mapping->big_page); return NvResult::Success; @@ -349,7 +358,8 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { return NvResult::BadValue; } - VAddr cpu_address{static_cast(handle->address + params.buffer_offset)}; + DAddr device_address{static_cast(nvmap.PinHandle(params.handle, sessions[fd], false) + + params.buffer_offset)}; u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; bool big_page{[&]() { @@ -373,15 +383,14 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { } const bool use_big_pages = alloc->second.big_pages && big_page; - gmmu->Map(params.offset, cpu_address, size, static_cast(params.kind), + gmmu->Map(params.offset, device_address, size, static_cast(params.kind), use_big_pages); - auto mapping{std::make_shared(cpu_address, params.offset, size, true, - use_big_pages, alloc->second.sparse)}; + auto mapping{std::make_shared(params.handle, device_address, params.offset, size, + true, use_big_pages, alloc->second.sparse)}; alloc->second.mappings.push_back(mapping); mapping_map[params.offset] = mapping; } else { - auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; @@ -394,18 +403,18 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { return NvResult::InsufficientMemory; } - gmmu->Map(params.offset, cpu_address, Common::AlignUp(size, page_size), + gmmu->Map(params.offset, device_address, Common::AlignUp(size, page_size), static_cast(params.kind), big_page); - auto mapping{ - std::make_shared(cpu_address, params.offset, size, false, big_page, false)}; + auto mapping{std::make_shared(params.handle, device_address, params.offset, size, + false, big_page, false)}; mapping_map[params.offset] = mapping; } return NvResult::Success; } -NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { +NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); std::scoped_lock lock(mutex); @@ -433,6 +442,8 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { gmmu->Unmap(params.offset, mapping->size); } + nvmap.UnpinHandle(mapping->handle); + mapping_map.erase(params.offset); } catch (const std::out_of_range&) { LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset); 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 0dd279f88..4b28f5078 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -141,9 +141,9 @@ private: NvResult AllocAsEx(IoctlAllocAsEx& params); NvResult AllocateSpace(IoctlAllocSpace& params); - NvResult Remap(std::span params); - NvResult MapBufferEx(IoctlMapBufferEx& params); - NvResult UnmapBuffer(IoctlUnmapBuffer& params); + NvResult Remap(std::span params, DeviceFD fd); + NvResult MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd); + NvResult UnmapBuffer(IoctlUnmapBuffer& params, DeviceFD fd); NvResult FreeSpace(IoctlFreeSpace& params); NvResult BindChannel(IoctlBindChannel& params); @@ -159,16 +159,18 @@ private: NvCore::NvMap& nvmap; struct Mapping { - VAddr ptr; + NvCore::NvMap::Handle::Id handle; + DAddr ptr; u64 offset; u64 size; bool fixed; bool big_page; // Only valid if fixed == false bool sparse_alloc; - Mapping(VAddr ptr_, u64 offset_, u64 size_, bool fixed_, bool big_page_, bool sparse_alloc_) - : ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), big_page(big_page_), - sparse_alloc(sparse_alloc_) {} + Mapping(NvCore::NvMap::Handle::Id handle_, DAddr ptr_, u64 offset_, u64 size_, bool fixed_, + bool big_page_, bool sparse_alloc_) + : handle(handle_), ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), + big_page(big_page_), sparse_alloc(sparse_alloc_) {} }; struct Allocation { @@ -212,9 +214,7 @@ private: bool initialised{}; } vm; std::shared_ptr gmmu; - - // s32 channel{}; - // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; + std::unordered_map sessions; }; } // namespace Service::Nvidia::Devices 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 9ab0ae4d8..78bc5f3c4 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -95,6 +95,9 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span data, De offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); auto& gpu = system.GPU(); + //auto& device_memory = system.Host1x().MemoryManager(); + auto* session = core.GetSession(sessions[fd]); + if (gpu.UseNvdec()) { for (std::size_t i = 0; i < syncpt_increments.size(); i++) { const SyncptIncr& syncpt_incr = syncpt_increments[i]; @@ -106,7 +109,7 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span data, De const auto object = nvmap.GetHandle(cmd_buffer.memory_id); ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); - system.ApplicationMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), + session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), cmdlist.size() * sizeof(u32)); gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); } @@ -136,7 +139,8 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) { NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span entries, DeviceFD fd) { const size_t num_entries = std::min(params.num_entries, static_cast(entries.size())); for (size_t i = 0; i < num_entries; i++) { - entries[i].map_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd]); + DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd], true); + entries[i].map_address = static_cast(pin_address); } return NvResult::Success; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 2b107f009..7765ca1be 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -123,8 +123,8 @@ NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) { return NvResult::InsufficientMemory; } - const auto result = file.AllocateHandle(params.handle, params.flags, params.align, params.kind, - params.address, sessions[fd]); + 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; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 492ad849a..6e4825313 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -13,8 +13,6 @@ #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvdrv_interface.h" -#pragma optimize("", off) - namespace Service::Nvidia { void NVDRV::Open(HLERequestContext& ctx) { @@ -173,8 +171,8 @@ void NVDRV::Initialize(HLERequestContext& ctx) { [[maybe_unused]] const auto transfer_memory_size = rp.Pop(); auto& container = nvdrv->GetContainer(); - auto process = ctx.GetObjectFromHandle(process_handle); - session_id = container.OpenSession(process->DynamicCast()); + auto process = ctx.GetObjectFromHandle(process_handle); + session_id = container.OpenSession(process.GetPointerUnsafe()); is_initialized = true; } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 8176a41be..609e775ae 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -24,6 +24,8 @@ #include "core/hle/kernel/k_process.h" #include "core/memory.h" #include "video_core/gpu.h" +#include "video_core/host1x/gpu_device_memory_manager.h" +#include "video_core/host1x/host1x.h" #include "video_core/rasterizer_download_area.h" namespace Core::Memory { @@ -638,15 +640,16 @@ struct Memory::Impl { base * YUZU_PAGESIZE, (base + size) * YUZU_PAGESIZE); // During boot, current_page_table might not be set yet, in which case we need not flush - if (system.IsPoweredOn()) { + /*if (system.IsPoweredOn()) { auto& gpu = system.GPU(); for (u64 i = 0; i < size; i++) { const auto page = base + i; if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) { + gpu.FlushAndInvalidateRegion(page << YUZU_PAGEBITS, YUZU_PAGESIZE); } } - } + }*/ const auto end = base + size; ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", @@ -811,10 +814,15 @@ struct Memory::Impl { return true; } - void HandleRasterizerDownload(VAddr address, size_t size) { + void HandleRasterizerDownload(VAddr v_address, size_t size) { + const auto* p = GetPointerImpl( + v_address, []() {}, []() {}); + auto& gpu_device_memory = system.Host1x().MemoryManager(); + DAddr address = + gpu_device_memory.GetAddressFromPAddr(system.DeviceMemory().GetRawPhysicalAddr(p)); const size_t core = system.GetCurrentHostThreadID(); auto& current_area = rasterizer_read_areas[core]; - const VAddr end_address = address + size; + const DAddr end_address = address + size; if (current_area.start_address <= address && end_address <= current_area.end_address) [[likely]] { return; @@ -822,7 +830,10 @@ struct Memory::Impl { current_area = system.GPU().OnCPURead(address, size); } - void HandleRasterizerWrite(VAddr address, size_t size) { + void HandleRasterizerWrite(VAddr v_address, size_t size) { + const auto* p = GetPointerImpl( + v_address, []() {}, []() {}); + PAddr address = system.DeviceMemory().GetRawPhysicalAddr(p); constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1; const size_t core = std::min(system.GetCurrentHostThreadID(), sys_core); // any other calls threads go to syscore. @@ -836,7 +847,7 @@ struct Memory::Impl { } }); auto& current_area = rasterizer_write_areas[core]; - VAddr subaddress = address >> YUZU_PAGEBITS; + PAddr subaddress = address >> YUZU_PAGEBITS; bool do_collection = current_area.last_address == subaddress; if (!do_collection) [[unlikely]] { do_collection = system.GPU().OnCPUWrite(address, size); @@ -849,7 +860,7 @@ struct Memory::Impl { } struct GPUDirtyState { - VAddr last_address; + PAddr last_address; }; void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { diff --git a/src/core/memory.h b/src/core/memory.h index dddfaf4a4..47ca6a35a 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -498,209 +498,4 @@ private: std::unique_ptr impl; }; -enum GuestMemoryFlags : u32 { - Read = 1 << 0, - Write = 1 << 1, - Safe = 1 << 2, - Cached = 1 << 3, - - SafeRead = Read | Safe, - SafeWrite = Write | Safe, - SafeReadWrite = SafeRead | SafeWrite, - SafeReadCachedWrite = SafeReadWrite | Cached, - - UnsafeRead = Read, - UnsafeWrite = Write, - UnsafeReadWrite = UnsafeRead | UnsafeWrite, - UnsafeReadCachedWrite = UnsafeReadWrite | Cached, -}; - -namespace { -template -class GuestMemory { - using iterator = T*; - using const_iterator = const T*; - using value_type = T; - using element_type = T; - using iterator_category = std::contiguous_iterator_tag; - -public: - GuestMemory() = delete; - explicit GuestMemory(M& memory, u64 addr, std::size_t size, - Common::ScratchBuffer* backup = nullptr) - : m_memory{memory}, m_addr{addr}, m_size{size} { - static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write); - if constexpr (FLAGS & GuestMemoryFlags::Read) { - Read(addr, size, backup); - } - } - - ~GuestMemory() = default; - - T* data() noexcept { - return m_data_span.data(); - } - - const T* data() const noexcept { - return m_data_span.data(); - } - - size_t size() const noexcept { - return m_size; - } - - size_t size_bytes() const noexcept { - return this->size() * sizeof(T); - } - - [[nodiscard]] T* begin() noexcept { - return this->data(); - } - - [[nodiscard]] const T* begin() const noexcept { - return this->data(); - } - - [[nodiscard]] T* end() noexcept { - return this->data() + this->size(); - } - - [[nodiscard]] const T* end() const noexcept { - return this->data() + this->size(); - } - - T& operator[](size_t index) noexcept { - return m_data_span[index]; - } - - const T& operator[](size_t index) const noexcept { - return m_data_span[index]; - } - - void SetAddressAndSize(u64 addr, std::size_t size) noexcept { - m_addr = addr; - m_size = size; - m_addr_changed = true; - } - - std::span Read(u64 addr, std::size_t size, - Common::ScratchBuffer* backup = nullptr) noexcept { - m_addr = addr; - m_size = size; - if (m_size == 0) { - m_is_data_copy = true; - return {}; - } - - if (this->TrySetSpan()) { - if constexpr (FLAGS & GuestMemoryFlags::Safe) { - m_memory.FlushRegion(m_addr, this->size_bytes()); - } - } else { - if (backup) { - backup->resize_destructive(this->size()); - m_data_span = *backup; - } else { - m_data_copy.resize(this->size()); - m_data_span = std::span(m_data_copy); - } - m_is_data_copy = true; - m_span_valid = true; - if constexpr (FLAGS & GuestMemoryFlags::Safe) { - m_memory.ReadBlock(m_addr, this->data(), this->size_bytes()); - } else { - m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes()); - } - } - return m_data_span; - } - - void Write(std::span write_data) noexcept { - if constexpr (FLAGS & GuestMemoryFlags::Cached) { - m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes()); - } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { - m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes()); - } else { - m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes()); - } - } - - bool TrySetSpan() noexcept { - if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) { - m_data_span = {reinterpret_cast(ptr), this->size()}; - m_span_valid = true; - return true; - } - return false; - } - -protected: - bool IsDataCopy() const noexcept { - return m_is_data_copy; - } - - bool AddressChanged() const noexcept { - return m_addr_changed; - } - - M& m_memory; - u64 m_addr{}; - size_t m_size{}; - std::span m_data_span{}; - std::vector m_data_copy{}; - bool m_span_valid{false}; - bool m_is_data_copy{false}; - bool m_addr_changed{false}; -}; - -template -class GuestMemoryScoped : public GuestMemory { -public: - GuestMemoryScoped() = delete; - explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size, - Common::ScratchBuffer* backup = nullptr) - : GuestMemory(memory, addr, size, backup) { - if constexpr (!(FLAGS & GuestMemoryFlags::Read)) { - if (!this->TrySetSpan()) { - if (backup) { - this->m_data_span = *backup; - this->m_span_valid = true; - this->m_is_data_copy = true; - } - } - } - } - - ~GuestMemoryScoped() { - if constexpr (FLAGS & GuestMemoryFlags::Write) { - if (this->size() == 0) [[unlikely]] { - return; - } - - if (this->AddressChanged() || this->IsDataCopy()) { - ASSERT(this->m_span_valid); - if constexpr (FLAGS & GuestMemoryFlags::Cached) { - this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes()); - } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { - this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes()); - } else { - this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes()); - } - } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || - (FLAGS & GuestMemoryFlags::Cached)) { - this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes()); - } - } - } -}; -} // namespace - -template -using CpuGuestMemory = GuestMemory; -template -using CpuGuestMemoryScoped = GuestMemoryScoped; -template -using GpuGuestMemory = GuestMemory; -template -using GpuGuestMemoryScoped = GuestMemoryScoped; } // namespace Core::Memory -- cgit v1.2.3 From 34a8d0cc8e04b4b9d8e5a75e552f0adb31b5d718 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 Dec 2023 07:53:52 +0100 Subject: SMMU: Implement physical memory mirroring --- src/core/device_memory_manager.h | 27 ++++- src/core/device_memory_manager.inc | 154 +++++++++++++++++++++++++- src/core/hle/service/nvdrv/core/container.cpp | 6 +- src/core/hle/service/nvdrv/core/nvmap.cpp | 7 +- src/core/hle/service/nvdrv/core/nvmap.h | 6 +- src/core/memory.cpp | 53 +++++---- 6 files changed, 221 insertions(+), 32 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index 1a63cbd09..7c7726348 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -10,8 +10,10 @@ #include #include "common/common_types.h" +#include "common/scratch_buffer.h" #include "common/virtual_buffer.h" + namespace Core { class DeviceMemory; @@ -49,9 +51,25 @@ public: template const T* GetPointer(DAddr address) const; - DAddr GetAddressFromPAddr(PAddr address) const { + template + void ApplyOpOnPAddr(PAddr address, Common::ScratchBuffer& buffer, Func&& operation) { DAddr subbits = static_cast(address & page_mask); - return (static_cast(compressed_device_addr[(address >> page_bits)]) << page_bits) + subbits; + const u32 base = compressed_device_addr[(address >> page_bits)]; + if ((base >> MULTI_FLAG_BITS) == 0) [[likely]] { + const DAddr d_address = static_cast(base << page_bits) + subbits; + operation(d_address); + return; + } + InnerGatherDeviceAddresses(buffer, address); + for (u32 value : buffer) { + operation(static_cast(value << page_bits) + subbits); + } + } + + template + void ApplyOpOnPointer(const u8* p, Common::ScratchBuffer& buffer, Func&& operation) { + PAddr address = GetRawPhysicalAddr(p); + ApplyOpOnPAddr(address, buffer, operation); } PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const { @@ -98,6 +116,9 @@ private: static constexpr size_t page_size = 1ULL << page_bits; static constexpr size_t page_mask = page_size - 1ULL; static constexpr u32 physical_address_base = 1U << page_bits; + static constexpr u32 MULTI_FLAG_BITS = 31; + static constexpr u32 MULTI_FLAG = 1U << MULTI_FLAG_BITS; + static constexpr u32 MULTI_MASK = ~MULTI_FLAG; template T* GetPointerFromRaw(PAddr addr) { @@ -117,6 +138,8 @@ private: void WalkBlock(const DAddr addr, const std::size_t size, auto on_unmapped, auto on_memory, auto increment); + void InnerGatherDeviceAddresses(Common::ScratchBuffer& buffer, PAddr address); + std::unique_ptr> impl; const uintptr_t physical_base; diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 8c5f82d31..4fb3ad3ab 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -18,10 +18,117 @@ namespace Core { +namespace { + +class PhysicalAddressContainer { +public: + PhysicalAddressContainer() = default; + ~PhysicalAddressContainer() = default; + + void GatherValues(u32 start_entry, Common::ScratchBuffer& buffer) { + buffer.resize(8); + buffer.resize(0); + size_t index = 0; + const auto add_value = [&](u32 value) { + buffer[index] = value; + index++; + buffer.resize(index); + }; + + u32 iter_entry = start_entry; + Entry* current = &storage[iter_entry - 1]; + add_value(current->value); + while (current->next_entry != 0) { + iter_entry = current->next_entry; + current = &storage[iter_entry - 1]; + add_value(current->value); + } + } + + u32 Register(u32 value) { + return RegisterImplementation(value); + } + + void Register(u32 value, u32 start_entry) { + auto entry_id = RegisterImplementation(value); + u32 iter_entry = start_entry; + Entry* current = &storage[iter_entry - 1]; + while (current->next_entry != 0) { + iter_entry = current->next_entry; + current = &storage[iter_entry - 1]; + } + current->next_entry = entry_id; + } + + std::pair Unregister(u32 value, u32 start_entry) { + u32 iter_entry = start_entry; + Entry* previous{}; + Entry* current = &storage[iter_entry - 1]; + Entry* next{}; + bool more_than_one_remaining = false; + u32 result_start{start_entry}; + size_t count = 0; + while (current->value != value) { + count++; + previous = current; + iter_entry = current->next_entry; + current = &storage[iter_entry - 1]; + } + // Find next + u32 next_entry = current->next_entry; + if (next_entry != 0) { + next = &storage[next_entry - 1]; + more_than_one_remaining = next->next_entry != 0; + } + if (previous) { + previous->next_entry = next_entry; + } else { + result_start = next_entry; + } + free_entries.emplace_back(iter_entry); + return std::make_pair(more_than_one_remaining || count > 1, result_start); + } + + u32 ReleaseEntry(u32 start_entry) { + Entry* current = &storage[start_entry - 1]; + free_entries.emplace_back(start_entry); + return current->value; + } + +private: + u32 RegisterImplementation(u32 value) { + auto entry_id = GetNewEntry(); + auto& entry = storage[entry_id - 1]; + entry.next_entry = 0; + entry.value = value; + return entry_id; + } + u32 GetNewEntry() { + if (!free_entries.empty()) { + u32 result = free_entries.front(); + free_entries.pop_front(); + return result; + } + storage.emplace_back(); + u32 new_entry = static_cast(storage.size()); + return new_entry; + } + + struct Entry { + u32 next_entry{}; + u32 value{}; + }; + + std::deque storage; + std::deque free_entries; +}; + struct EmptyAllocator { EmptyAllocator([[maybe_unused]] DAddr address) {} }; +} // namespace + template struct DeviceMemoryManagerAllocator { static constexpr bool supports_pinning = DTraits::supports_pinning; @@ -38,6 +145,7 @@ struct DeviceMemoryManagerAllocator { std::conditional_t, EmptyAllocator> pin_allocator; Common::FlatAllocator main_allocator; + PhysicalAddressContainer multi_dev_address; /// Returns true when vaddr -> vaddr+size is fully contained in the buffer template @@ -109,6 +217,9 @@ DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memo cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) { impl = std::make_unique>(); cached_pages = std::make_unique(); + for (size_t i = 0; i < 1ULL << (33 - 12); i++) { + compressed_device_addr[i] = 0; + } } template @@ -155,8 +266,19 @@ void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size } auto phys_addr = static_cast(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U; compressed_physical_ptr[start_page_d + i] = phys_addr; - compressed_device_addr[phys_addr - 1U] = static_cast(start_page_d + i); InsertCPUBacking(start_page_d + i, new_vaddress, process_id); + const u32 base_dev = compressed_device_addr[phys_addr - 1U]; + const u32 new_dev = static_cast(start_page_d + i); + if (base_dev == 0) [[likely]] { + compressed_device_addr[phys_addr - 1U] = new_dev; + continue; + } + u32 start_id = base_dev & MULTI_MASK; + if ((base_dev >> MULTI_FLAG_BITS) == 0) { + start_id = impl->multi_dev_address.Register(base_dev); + compressed_device_addr[phys_addr - 1U] = MULTI_FLAG | start_id; + } + impl->multi_dev_address.Register(new_dev, start_id); } } @@ -170,12 +292,38 @@ void DeviceMemoryManager::Unmap(DAddr address, size_t size) { auto phys_addr = compressed_physical_ptr[start_page_d + i]; compressed_physical_ptr[start_page_d + i] = 0; cpu_backing_address[start_page_d + i] = 0; - if (phys_addr != 0) { - compressed_device_addr[phys_addr - 1] = 0; + if (phys_addr != 0) [[likely]] { + const u32 base_dev = compressed_device_addr[phys_addr - 1U]; + if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] { + compressed_device_addr[phys_addr - 1] = 0; + continue; + } + const auto [more_entries, new_start] = impl->multi_dev_address.Unregister( + static_cast(start_page_d + i), base_dev & MULTI_MASK); + if (!more_entries) { + compressed_device_addr[phys_addr - 1] = + impl->multi_dev_address.ReleaseEntry(new_start); + continue; + } + compressed_device_addr[phys_addr - 1] = new_start | MULTI_FLAG; } } } +template +void DeviceMemoryManager::InnerGatherDeviceAddresses(Common::ScratchBuffer& buffer, + PAddr address) { + size_t phys_addr = address >> page_bits; + std::scoped_lock lk(mapping_guard); + u32 backing = compressed_device_addr[phys_addr]; + if ((backing >> MULTI_FLAG_BITS) != 0) { + impl->multi_dev_address.GatherValues(backing & MULTI_MASK, buffer); + return; + } + buffer.resize(1); + buffer[0] = backing; +} + template template T* DeviceMemoryManager::GetPointer(DAddr address) { diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index 7c2231fe6..e12ce05c1 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -16,8 +16,8 @@ namespace Service::Nvidia::NvCore { struct ContainerImpl { - explicit ContainerImpl(Tegra::Host1x::Host1x& host1x_) - : host1x{host1x_}, file{host1x_}, manager{host1x_}, device_file_data{} {} + explicit ContainerImpl(Container& core, Tegra::Host1x::Host1x& host1x_) + : host1x{host1x_}, file{core, host1x_}, manager{host1x_}, device_file_data{} {} Tegra::Host1x::Host1x& host1x; NvMap file; SyncpointManager manager; @@ -29,7 +29,7 @@ struct ContainerImpl { }; Container::Container(Tegra::Host1x::Host1x& host1x_) { - impl = std::make_unique(host1x_); + impl = std::make_unique(*this, host1x_); } Container::~Container() = default; diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 7879c6f04..e4168a37c 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -7,6 +7,7 @@ #include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/memory.h" #include "video_core/host1x/host1x.h" @@ -64,7 +65,7 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) { return NvResult::Success; } -NvMap::NvMap(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {} +NvMap::NvMap(Container& core_, Tegra::Host1x::Host1x& host1x_) : host1x{host1x_}, core{core_} {} void NvMap::AddHandle(std::shared_ptr handle_description) { std::scoped_lock lock(handles_lock); @@ -160,6 +161,8 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are // If not then allocate some space and map it DAddr address{}; auto& smmu = host1x.MemoryManager(); + auto* session = core.GetSession(session_id); + auto allocate = std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); //: std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); while ((address = allocate(static_cast(handle_description->aligned_size))) == 0) { @@ -179,7 +182,7 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are handle_description->d_address = address; smmu.Map(address, handle_description->address, handle_description->aligned_size, - session_id); + session->smmu_id); } handle_description->pins++; diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index e9e9e8b5b..7dd6d26c3 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -25,6 +25,8 @@ class Host1x; } // namespace Tegra namespace Service::Nvidia::NvCore { + +class Container; /** * @brief The nvmap core class holds the global state for nvmap and provides methods to manage * handles @@ -109,7 +111,7 @@ public: bool can_unlock; //!< If the address region is ready to be unlocked }; - explicit NvMap(Tegra::Host1x::Host1x& host1x); + explicit NvMap(Container& core, Tegra::Host1x::Host1x& host1x); /** * @brief Creates an unallocated handle of the given size @@ -173,5 +175,7 @@ private: * @return If the handle was removed from the map */ bool TryRemoveHandle(const Handle& handle_description); + + Container& core; }; } // namespace Service::Nvidia::NvCore diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 609e775ae..f126840cb 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -44,7 +44,8 @@ bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessA // from outside classes. This also allows modification to the internals of the memory // subsystem without needing to rebuild all files that make use of the memory interface. struct Memory::Impl { - explicit Impl(Core::System& system_) : system{system_} {} + explicit Impl(Core::System& system_) + : system{system_} {} void SetCurrentPageTable(Kernel::KProcess& process) { current_page_table = &process.GetPageTable().GetImpl(); @@ -817,26 +818,31 @@ struct Memory::Impl { void HandleRasterizerDownload(VAddr v_address, size_t size) { const auto* p = GetPointerImpl( v_address, []() {}, []() {}); - auto& gpu_device_memory = system.Host1x().MemoryManager(); - DAddr address = - gpu_device_memory.GetAddressFromPAddr(system.DeviceMemory().GetRawPhysicalAddr(p)); + if (!gpu_device_memory) [[unlikely]] { + gpu_device_memory = &system.Host1x().MemoryManager(); + } const size_t core = system.GetCurrentHostThreadID(); auto& current_area = rasterizer_read_areas[core]; - const DAddr end_address = address + size; - if (current_area.start_address <= address && end_address <= current_area.end_address) - [[likely]] { - return; - } - current_area = system.GPU().OnCPURead(address, size); + gpu_device_memory->ApplyOpOnPointer( + p, scratch_buffers[core], [&](DAddr address) { + const DAddr end_address = address + size; + if (current_area.start_address <= address && end_address <= current_area.end_address) + [[likely]] { + return; + } + current_area = system.GPU().OnCPURead(address, size); + }); } void HandleRasterizerWrite(VAddr v_address, size_t size) { const auto* p = GetPointerImpl( v_address, []() {}, []() {}); - PAddr address = system.DeviceMemory().GetRawPhysicalAddr(p); constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1; const size_t core = std::min(system.GetCurrentHostThreadID(), sys_core); // any other calls threads go to syscore. + if (!gpu_device_memory) [[unlikely]] { + gpu_device_memory = &system.Host1x().MemoryManager(); + } // Guard on sys_core; if (core == sys_core) [[unlikely]] { sys_core_guard.lock(); @@ -846,17 +852,20 @@ struct Memory::Impl { sys_core_guard.unlock(); } }); - auto& current_area = rasterizer_write_areas[core]; - PAddr subaddress = address >> YUZU_PAGEBITS; - bool do_collection = current_area.last_address == subaddress; - if (!do_collection) [[unlikely]] { - do_collection = system.GPU().OnCPUWrite(address, size); - if (!do_collection) { - return; + gpu_device_memory->ApplyOpOnPointer( + p, scratch_buffers[core], [&](DAddr address) { + auto& current_area = rasterizer_write_areas[core]; + PAddr subaddress = address >> YUZU_PAGEBITS; + bool do_collection = current_area.last_address == subaddress; + if (!do_collection) [[unlikely]] { + do_collection = system.GPU().OnCPUWrite(address, size); + if (!do_collection) { + return; + } + current_area.last_address = subaddress; } - current_area.last_address = subaddress; - } - gpu_dirty_managers[core].Collect(address, size); + gpu_dirty_managers[core].Collect(address, size); + }); } struct GPUDirtyState { @@ -872,10 +881,12 @@ struct Memory::Impl { } Core::System& system; + Tegra::MaxwellDeviceMemoryManager* gpu_device_memory{}; Common::PageTable* current_page_table = nullptr; std::array rasterizer_read_areas{}; std::array rasterizer_write_areas{}; + std::array, Core::Hardware::NUM_CPU_CORES> scratch_buffers{}; std::span gpu_dirty_managers; std::mutex sys_core_guard; -- cgit v1.2.3 From bad705f245f1591d8a92cd57bfbc87dd2cdb0fea Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 Dec 2023 09:27:37 +0100 Subject: SMMU: Fix Unregister on MultiAddress --- src/core/device_memory_manager.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 4fb3ad3ab..b3a5f3d8b 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -78,7 +78,7 @@ public: u32 next_entry = current->next_entry; if (next_entry != 0) { next = &storage[next_entry - 1]; - more_than_one_remaining = next->next_entry != 0; + more_than_one_remaining = next->next_entry != 0 || previous != nullptr; } if (previous) { previous->next_entry = next_entry; -- cgit v1.2.3 From 96fd1348aea9d70cb502a94cbd0412be6edb0189 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 Dec 2023 09:50:04 +0100 Subject: GPU SMMU: Expand to 34 bits --- src/core/hle/service/nvdrv/core/nvmap.cpp | 38 +++++++++++++++++++--- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 1 - 2 files changed, 34 insertions(+), 5 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index e4168a37c..0b2ddd980 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -80,6 +80,15 @@ void NvMap::UnmapHandle(Handle& handle_description) { handle_description.unmap_queue_entry.reset(); } + // Free and unmap the handle from Host1x GMMU + if (handle_description.pin_virt_address) { + host1x.GMMU().Unmap(static_cast(handle_description.pin_virt_address), + handle_description.aligned_size); + host1x.Allocator().Free(handle_description.pin_virt_address, + static_cast(handle_description.aligned_size)); + handle_description.pin_virt_address = 0; + } + // Free and unmap the handle from the SMMU auto& smmu = host1x.MemoryManager(); smmu.Unmap(handle_description.d_address, handle_description.aligned_size); @@ -141,6 +150,17 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are } std::scoped_lock lock(handle_description->mutex); + const auto map_low_area = [&] { + if (handle_description->pin_virt_address == 0) { + auto& gmmu_allocator = host1x.Allocator(); + auto& gmmu = host1x.GMMU(); + u32 address = + gmmu_allocator.Allocate(static_cast(handle_description->aligned_size)); + gmmu.Map(static_cast(address), handle_description->d_address, + handle_description->aligned_size); + handle_description->pin_virt_address = address; + } + }; if (!handle_description->pins) { // If we're in the unmap queue we can just remove ourselves and return since we're already // mapped @@ -152,6 +172,12 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are unmap_queue.erase(*handle_description->unmap_queue_entry); handle_description->unmap_queue_entry.reset(); + if (low_area_pin) { + map_low_area(); + handle_description->pins++; + return static_cast(handle_description->pin_virt_address); + } + handle_description->pins++; return handle_description->d_address; } @@ -162,10 +188,7 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are DAddr address{}; auto& smmu = host1x.MemoryManager(); auto* session = core.GetSession(session_id); - - auto allocate = std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); - //: std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); - while ((address = allocate(static_cast(handle_description->aligned_size))) == 0) { + while ((address = smmu.Allocate(handle_description->aligned_size)) == 0) { // Free handles until the allocation succeeds std::scoped_lock queueLock(unmap_queue_lock); if (auto freeHandleDesc{unmap_queue.front()}) { @@ -185,7 +208,14 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are session->smmu_id); } + if (low_area_pin) { + map_low_area(); + } + handle_description->pins++; + if (low_area_pin) { + return static_cast(handle_description->pin_virt_address); + } return handle_description->d_address; } 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 78bc5f3c4..0b6aa9993 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -95,7 +95,6 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span data, De offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); auto& gpu = system.GPU(); - //auto& device_memory = system.Host1x().MemoryManager(); auto* session = core.GetSession(sessions[fd]); if (gpu.UseNvdec()) { -- cgit v1.2.3 From 0adc09e0afcde345a5303efd73b3b7737245a7d9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 30 Dec 2023 03:36:24 +0100 Subject: GPU-SMMU: Estimate game leak and preallocate device region. --- src/core/CMakeLists.txt | 2 + src/core/device_memory_manager.inc | 8 +- src/core/hle/service/nvdrv/core/container.cpp | 62 ++++++++- src/core/hle/service/nvdrv/core/container.h | 4 + src/core/hle/service/nvdrv/core/heap_mapper.cpp | 172 ++++++++++++++++++++++++ src/core/hle/service/nvdrv/core/heap_mapper.h | 48 +++++++ src/core/hle/service/nvdrv/core/nvmap.cpp | 56 +++++--- src/core/hle/service/nvdrv/core/nvmap.h | 2 + 8 files changed, 329 insertions(+), 25 deletions(-) create mode 100644 src/core/hle/service/nvdrv/core/heap_mapper.cpp create mode 100644 src/core/hle/service/nvdrv/core/heap_mapper.h (limited to 'src/core') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ca54eb6c6..0f713ead1 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -611,6 +611,8 @@ add_library(core STATIC hle/service/ns/pdm_qry.h hle/service/nvdrv/core/container.cpp hle/service/nvdrv/core/container.h + hle/service/nvdrv/core/heap_mapper.cpp + hle/service/nvdrv/core/heap_mapper.h hle/service/nvdrv/core/nvmap.cpp hle/service/nvdrv/core/nvmap.h hle/service/nvdrv/core/syncpoint_manager.cpp diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index b3a5f3d8b..138eb5017 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -20,10 +20,10 @@ namespace Core { namespace { -class PhysicalAddressContainer { +class MultiAddressContainer { public: - PhysicalAddressContainer() = default; - ~PhysicalAddressContainer() = default; + MultiAddressContainer() = default; + ~MultiAddressContainer() = default; void GatherValues(u32 start_entry, Common::ScratchBuffer& buffer) { buffer.resize(8); @@ -145,7 +145,7 @@ struct DeviceMemoryManagerAllocator { std::conditional_t, EmptyAllocator> pin_allocator; Common::FlatAllocator main_allocator; - PhysicalAddressContainer multi_dev_address; + MultiAddressContainer multi_dev_address; /// Returns true when vaddr -> vaddr+size is fully contained in the buffer template diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index e12ce05c1..ba7eb9e24 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/heap_mapper.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" #include "core/memory.h" @@ -36,6 +37,14 @@ Container::~Container() = default; size_t Container::OpenSession(Kernel::KProcess* process) { std::scoped_lock lk(impl->session_guard); + for (auto& session : impl->sessions) { + if (!session.is_active) { + continue; + } + if (session.process == process) { + return session.id; + } + } size_t new_id{}; auto* memory_interface = &process->GetMemory(); auto& smmu = impl->host1x.MemoryManager(); @@ -48,16 +57,65 @@ size_t Container::OpenSession(Kernel::KProcess* process) { impl->sessions.emplace_back(new_id, process, smmu_id); new_id = impl->new_ids++; } - LOG_CRITICAL(Debug, "Created Session {}", new_id); + auto& session = impl->sessions[new_id]; + session.is_active = true; + // Optimization + if (process->IsApplication()) { + auto& page_table = process->GetPageTable().GetBasePageTable(); + auto heap_start = page_table.GetHeapRegionStart(); + + Kernel::KProcessAddress cur_addr = heap_start; + size_t region_size = 0; + VAddr region_start = 0; + while (true) { + Kernel::KMemoryInfo mem_info{}; + Kernel::Svc::PageInfo page_info{}; + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), + cur_addr)); + auto svc_mem_info = mem_info.GetSvcMemoryInfo(); + + // check if this memory block is heap + if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { + if (svc_mem_info.size > region_size) { + region_size = svc_mem_info.size; + region_start = svc_mem_info.base_address; + } + } + + // Check if we're done. + const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size; + if (next_address <= GetInteger(cur_addr)) { + break; + } + + cur_addr = next_address; + } + session.has_preallocated_area = false; + auto start_region = (region_size >> 15) >= 1024 ? smmu.Allocate(region_size) : 0; + if (start_region != 0) { + session.mapper = std::make_unique(region_start, start_region, region_size, + smmu_id, impl->host1x); + session.has_preallocated_area = true; + LOG_CRITICAL(Debug, "Preallocation created!"); + } + } return new_id; } void Container::CloseSession(size_t id) { std::scoped_lock lk(impl->session_guard); + auto& session = impl->sessions[id]; auto& smmu = impl->host1x.MemoryManager(); + if (session.has_preallocated_area) { + const DAddr region_start = session.mapper->GetRegionStart(); + const size_t region_size = session.mapper->GetRegionSize(); + session.mapper.reset(); + smmu.Free(region_start, region_size); + session.has_preallocated_area = false; + } + session.is_active = false; smmu.UnregisterProcess(impl->sessions[id].smmu_id); impl->id_pool.emplace_front(id); - LOG_CRITICAL(Debug, "Closed Session {}", id); } Session* Container::GetSession(size_t id) { diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index a1fd20199..86705cbc8 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -20,6 +20,7 @@ class Host1x; namespace Service::Nvidia::NvCore { +class HeapMapper; class NvMap; class SyncpointManager; @@ -29,6 +30,9 @@ struct Session { size_t id; Kernel::KProcess* process; size_t smmu_id; + bool has_preallocated_area{}; + std::unique_ptr mapper{}; + bool is_active{}; }; class Container { diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.cpp b/src/core/hle/service/nvdrv/core/heap_mapper.cpp new file mode 100644 index 000000000..59d993bc6 --- /dev/null +++ b/src/core/hle/service/nvdrv/core/heap_mapper.cpp @@ -0,0 +1,172 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include +#define BOOST_NO_MT +#include +#undef BOOST_NO_MT +#include +#include +#include +#include +#include +#include +#include + +#include "core/hle/service/nvdrv/core/heap_mapper.h" +#include "video_core/host1x/host1x.h" + +namespace boost { +template +class fast_pool_allocator; +} + +namespace Service::Nvidia::NvCore { + +using IntervalCompare = std::less; +using IntervalInstance = boost::icl::interval_type_default; +using IntervalAllocator = boost::fast_pool_allocator; +using IntervalSet = boost::icl::interval_set; +using IntervalType = typename IntervalSet::interval_type; + +template +struct counter_add_functor : public boost::icl::identity_based_inplace_combine { + // types + typedef counter_add_functor type; + typedef boost::icl::identity_based_inplace_combine base_type; + + // public member functions + void operator()(Type& current, const Type& added) const { + current += added; + if (current < base_type::identity_element()) { + current = base_type::identity_element(); + } + } + + // public static functions + static void version(Type&){}; +}; + +using OverlapCombine = counter_add_functor; +using OverlapSection = boost::icl::inter_section; +using OverlapCounter = boost::icl::split_interval_map; + +struct HeapMapper::HeapMapperInternal { + HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : device_memory{host1x.MemoryManager()} {} + ~HeapMapperInternal() = default; + + template + void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size, + Func&& func) { + const DAddr start_address = cpu_addr; + const DAddr end_address = start_address + size; + const IntervalType search_interval{start_address, end_address}; + auto it = current_range.lower_bound(search_interval); + if (it == current_range.end()) { + return; + } + auto end_it = current_range.upper_bound(search_interval); + for (; it != end_it; it++) { + auto& inter = it->first; + DAddr inter_addr_end = inter.upper(); + DAddr inter_addr = inter.lower(); + if (inter_addr_end > end_address) { + inter_addr_end = end_address; + } + if (inter_addr < start_address) { + inter_addr = start_address; + } + func(inter_addr, inter_addr_end, it->second); + } + } + + void RemoveEachInOverlapCounter(OverlapCounter& current_range, + const IntervalType search_interval, int subtract_value) { + bool any_removals = false; + current_range.add(std::make_pair(search_interval, subtract_value)); + do { + any_removals = false; + auto it = current_range.lower_bound(search_interval); + if (it == current_range.end()) { + return; + } + auto end_it = current_range.upper_bound(search_interval); + for (; it != end_it; it++) { + if (it->second <= 0) { + any_removals = true; + current_range.erase(it); + break; + } + } + } while (any_removals); + } + + IntervalSet base_set; + OverlapCounter mapping_overlaps; + Tegra::MaxwellDeviceMemoryManager& device_memory; + std::mutex guard; +}; + +HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id, + Tegra::Host1x::Host1x& host1x) + : m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_smmu_id{smmu_id} { + m_internal = std::make_unique(host1x); +} + +HeapMapper::~HeapMapper() { + m_internal->device_memory.Unmap(m_daddress, m_size); +} + +DAddr HeapMapper::Map(VAddr start, size_t size) { + std::scoped_lock lk(m_internal->guard); + m_internal->base_set.clear(); + const IntervalType interval{start, start + size}; + m_internal->base_set.insert(interval); + m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, [this](VAddr start_addr, VAddr end_addr, int){ + const IntervalType other{start_addr, end_addr}; + m_internal->base_set.subtract(other); + }); + if (!m_internal->base_set.empty()) { + auto it = m_internal->base_set.begin(); + auto end_it = m_internal->base_set.end(); + for (; it != end_it; it++) { + const VAddr inter_addr_end = it->upper(); + const VAddr inter_addr = it->lower(); + const size_t offset = inter_addr - m_vaddress; + const size_t sub_size = inter_addr_end - inter_addr; + m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, m_smmu_id); + } + } + m_internal->mapping_overlaps += std::make_pair(interval, 1); + m_internal->base_set.clear(); + return m_daddress + (start - m_vaddress); +} + +void HeapMapper::Unmap(VAddr start, size_t size) { + std::scoped_lock lk(m_internal->guard); + m_internal->base_set.clear(); + m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, [this](VAddr start_addr, VAddr end_addr, int value) { + if (value <= 1) { + const IntervalType other{start_addr, end_addr}; + m_internal->base_set.insert(other); + } + }); + if (!m_internal->base_set.empty()) { + auto it = m_internal->base_set.begin(); + auto end_it = m_internal->base_set.end(); + for (; it != end_it; it++) { + const VAddr inter_addr_end = it->upper(); + const VAddr inter_addr = it->lower(); + const size_t offset = inter_addr - m_vaddress; + const size_t sub_size = inter_addr_end - inter_addr; + m_internal->device_memory.Unmap(m_daddress + offset, sub_size); + } + } + const IntervalType to_remove{start, start + size}; + m_internal->RemoveEachInOverlapCounter(m_internal->mapping_overlaps, to_remove, -1); + m_internal->base_set.clear(); +} + +} // namespace Service::Nvidia::NvCore \ No newline at end of file diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.h b/src/core/hle/service/nvdrv/core/heap_mapper.h new file mode 100644 index 000000000..8b23638b8 --- /dev/null +++ b/src/core/hle/service/nvdrv/core/heap_mapper.h @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +#include "common/common_types.h" + +namespace Tegra::Host1x { +class Host1x; +} // namespace Tegra::Host1x + +namespace Service::Nvidia::NvCore { + +class HeapMapper { +public: + HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id, + Tegra::Host1x::Host1x& host1x); + ~HeapMapper(); + + bool IsInBounds(VAddr start, size_t size) const { + VAddr end = start + size; + return start >= m_vaddress && end <= (m_vaddress + m_size); + } + + DAddr Map(VAddr start, size_t size); + + void Unmap(VAddr start, size_t size); + + DAddr GetRegionStart() const { + return m_daddress; + } + + size_t GetRegionSize() const { + return m_size; + } + +private: + struct HeapMapperInternal; + VAddr m_vaddress; + DAddr m_daddress; + size_t m_size; + size_t m_smmu_id; + std::unique_ptr m_internal; +}; + +} // namespace Service::Nvidia::NvCore \ No newline at end of file diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 0b2ddd980..023c070d9 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -8,10 +8,12 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/heap_mapper.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/memory.h" #include "video_core/host1x/host1x.h" + using Core::Memory::YUZU_PAGESIZE; namespace Service::Nvidia::NvCore { @@ -90,10 +92,19 @@ void NvMap::UnmapHandle(Handle& handle_description) { } // Free and unmap the handle from the SMMU - auto& smmu = host1x.MemoryManager(); - smmu.Unmap(handle_description.d_address, handle_description.aligned_size); - smmu.Free(handle_description.d_address, static_cast(handle_description.aligned_size)); + const size_t map_size = handle_description.aligned_size; + if (!handle_description.in_heap) { + auto& smmu = host1x.MemoryManager(); + smmu.Unmap(handle_description.d_address, map_size); + smmu.Free(handle_description.d_address, static_cast(map_size)); + handle_description.d_address = 0; + return; + } + const VAddr vaddress = handle_description.address; + auto* session = core.GetSession(handle_description.session_id); + session->mapper->Unmap(vaddress, map_size); handle_description.d_address = 0; + handle_description.in_heap = false; } bool NvMap::TryRemoveHandle(const Handle& handle_description) { @@ -188,24 +199,31 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are DAddr address{}; auto& smmu = host1x.MemoryManager(); auto* session = core.GetSession(session_id); - while ((address = smmu.Allocate(handle_description->aligned_size)) == 0) { - // 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 (handle_description->d_address) - UnmapHandle(*freeHandleDesc); - } else { - LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); + const VAddr vaddress = handle_description->address; + const size_t map_size = handle_description->aligned_size; + handle_description->session_id = session_id; + if (session->has_preallocated_area && session->mapper->IsInBounds(vaddress, map_size)) { + handle_description->d_address = session->mapper->Map(vaddress, map_size); + handle_description->in_heap = true; + } else { + while ((address = smmu.Allocate(map_size)) == 0) { + // 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 (handle_description->d_address) + UnmapHandle(*freeHandleDesc); + } else { + LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); + } } - } - handle_description->d_address = address; - - smmu.Map(address, handle_description->address, handle_description->aligned_size, - session->smmu_id); + handle_description->d_address = address; + smmu.Map(address, vaddress, map_size, session->smmu_id); + handle_description->in_heap = false; + } } if (low_area_pin) { diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 7dd6d26c3..4af61289e 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -70,6 +70,8 @@ public: u8 kind{}; //!< Used for memory compression bool allocated{}; //!< If the handle has been allocated with `Alloc` + bool in_heap{}; + size_t session_id{}; DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, //!< this can also be in the nvdrv tmem -- cgit v1.2.3 From 303cd311621b25fbb8d55e0ed2cc4c3248de44ad Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 30 Dec 2023 04:37:25 +0100 Subject: SMMU: Add Android compatibility --- src/core/device_memory_manager.inc | 7 +-- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 6 ++- src/core/memory.cpp | 62 +++++++++------------- src/core/memory.h | 4 +- 4 files changed, 34 insertions(+), 45 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 138eb5017..4f883cece 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -217,9 +217,6 @@ DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memo cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) { impl = std::make_unique>(); cached_pages = std::make_unique(); - for (size_t i = 0; i < 1ULL << (33 - 12); i++) { - compressed_device_addr[i] = 0; - } } template @@ -517,7 +514,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size u64 cache_begin = 0; u64 uncache_bytes = 0; u64 cache_bytes = 0; - const auto* MarkRegionCaching = &DeviceMemoryManager::DeviceMethods::MarkRegionCaching; + const auto MarkRegionCaching = &DeviceMemoryManager::DeviceMethods::MarkRegionCaching; std::atomic_thread_fence(std::memory_order_acquire); const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); @@ -577,4 +574,4 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size } } -} // namespace Core \ No newline at end of file +} // namespace Core 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 0b6aa9993..a50577c75 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -8,6 +8,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/kernel/k_process.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" @@ -109,7 +110,7 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span data, De ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), - cmdlist.size() * sizeof(u32)); + cmdlist.size() * sizeof(u32)); gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); } // Some games expect command_buffers to be written back @@ -135,7 +136,8 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) { return NvResult::Success; } -NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span entries, DeviceFD fd) { +NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span entries, + DeviceFD fd) { const size_t num_entries = std::min(params.num_entries, static_cast(entries.size())); for (size_t i = 0; i < num_entries; i++) { DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd], true); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index f126840cb..1c218566f 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -44,8 +44,7 @@ bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessA // from outside classes. This also allows modification to the internals of the memory // subsystem without needing to rebuild all files that make use of the memory interface. struct Memory::Impl { - explicit Impl(Core::System& system_) - : system{system_} {} + explicit Impl(Core::System& system_) : system{system_} {} void SetCurrentPageTable(Kernel::KProcess& process) { current_page_table = &process.GetPageTable().GetImpl(); @@ -640,18 +639,6 @@ struct Memory::Impl { LOG_DEBUG(HW_Memory, "Mapping {:016X} onto {:016X}-{:016X}", GetInteger(target), base * YUZU_PAGESIZE, (base + size) * YUZU_PAGESIZE); - // During boot, current_page_table might not be set yet, in which case we need not flush - /*if (system.IsPoweredOn()) { - auto& gpu = system.GPU(); - for (u64 i = 0; i < size; i++) { - const auto page = base + i; - if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) { - - gpu.FlushAndInvalidateRegion(page << YUZU_PAGEBITS, YUZU_PAGESIZE); - } - } - }*/ - const auto end = base + size; ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", base + page_table.pointers.size()); @@ -823,8 +810,7 @@ struct Memory::Impl { } const size_t core = system.GetCurrentHostThreadID(); auto& current_area = rasterizer_read_areas[core]; - gpu_device_memory->ApplyOpOnPointer( - p, scratch_buffers[core], [&](DAddr address) { + gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { const DAddr end_address = address + size; if (current_area.start_address <= address && end_address <= current_area.end_address) [[likely]] { @@ -852,8 +838,7 @@ struct Memory::Impl { sys_core_guard.unlock(); } }); - gpu_device_memory->ApplyOpOnPointer( - p, scratch_buffers[core], [&](DAddr address) { + gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { auto& current_area = rasterizer_write_areas[core]; PAddr subaddress = address >> YUZU_PAGEBITS; bool do_collection = current_area.last_address == subaddress; @@ -872,12 +857,25 @@ struct Memory::Impl { PAddr last_address; }; - void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { - system.GPU().InvalidateRegion(GetInteger(dest_addr), size); - } - - void FlushRegion(Common::ProcessAddress dest_addr, size_t size) { - system.GPU().FlushRegion(GetInteger(dest_addr), size); + void InvalidateGPUMemory(u8* p, size_t size) { + constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1; + const size_t core = std::min(system.GetCurrentHostThreadID(), + sys_core); // any other calls threads go to syscore. + if (!gpu_device_memory) [[unlikely]] { + gpu_device_memory = &system.Host1x().MemoryManager(); + } + // Guard on sys_core; + if (core == sys_core) [[unlikely]] { + sys_core_guard.lock(); + } + SCOPE_EXIT({ + if (core == sys_core) [[unlikely]] { + sys_core_guard.unlock(); + } + }); + auto& gpu = system.GPU(); + gpu_device_memory->ApplyOpOnPointer( + p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); }); } Core::System& system; @@ -1081,14 +1079,6 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug) impl->MarkRegionDebug(GetInteger(vaddr), size, debug); } -void Memory::InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { - impl->InvalidateRegion(dest_addr, size); -} - -void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) { - impl->FlushRegion(dest_addr, size); -} - bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { [[maybe_unused]] bool mapped = true; [[maybe_unused]] bool rasterizer = false; @@ -1100,10 +1090,10 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { GetInteger(vaddr)); mapped = false; }, - [&] { - impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size); - rasterizer = true; - }); + [&] { rasterizer = true; }); + if (rasterizer) { + impl->InvalidateGPUMemory(ptr, size); + } #ifdef __linux__ if (!rasterizer && mapped) { diff --git a/src/core/memory.h b/src/core/memory.h index 47ca6a35a..9d29cfd3f 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -486,10 +486,10 @@ public: void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); void SetGPUDirtyManagers(std::span managers); - void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size); + bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); + bool InvalidateSeparateHeap(void* fault_address); - void FlushRegion(Common::ProcessAddress dest_addr, size_t size); private: Core::System& system; -- cgit v1.2.3 From 9b11b9dce58b144d7f4407677a5e2dd52ca1888c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 30 Dec 2023 08:20:29 +0100 Subject: SMMU: Simplify and remove old code. --- src/core/device_memory_manager.h | 14 ++++---- src/core/device_memory_manager.inc | 69 ++++---------------------------------- 2 files changed, 13 insertions(+), 70 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index 7c7726348..0273b78db 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -38,7 +38,6 @@ public: DAddr Allocate(size_t size); void AllocateFixed(DAddr start, size_t size); - DAddr AllocatePinned(size_t size); void Free(DAddr start, size_t size); void Map(DAddr address, VAddr virtual_address, size_t size, size_t process_id); @@ -108,7 +107,6 @@ public: static constexpr size_t AS_BITS = Traits::device_virtual_bits; private: - static constexpr bool supports_pinning = Traits::supports_pinning; static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; static constexpr size_t device_as_size = 1ULL << device_virtual_bits; static constexpr size_t physical_max_bits = 33; @@ -167,28 +165,28 @@ private: } void InsertCPUBacking(size_t page_index, VAddr address, size_t process_id) { - cpu_backing_address[page_index] = address | (process_id << page_index); + cpu_backing_address[page_index] = address | (process_id << process_id_start_bit); } Common::VirtualBuffer cpu_backing_address; - static constexpr size_t subentries = 4; + static constexpr size_t subentries = 8 / sizeof(u8); static constexpr size_t subentries_mask = subentries - 1; class CounterEntry final { public: CounterEntry() = default; - std::atomic_uint16_t& Count(std::size_t page) { + std::atomic_uint8_t& Count(std::size_t page) { return values[page & subentries_mask]; } - const std::atomic_uint16_t& Count(std::size_t page) const { + const std::atomic_uint8_t& Count(std::size_t page) const { return values[page & subentries_mask]; } private: - std::array values{}; + std::array values{}; }; - static_assert(sizeof(CounterEntry) == subentries * sizeof(u16), + static_assert(sizeof(CounterEntry) == subentries * sizeof(u8), "CounterEntry should be 8 bytes!"); static constexpr size_t num_counter_entries = diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 4f883cece..e9d0efe19 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -131,81 +131,31 @@ struct EmptyAllocator { template struct DeviceMemoryManagerAllocator { - static constexpr bool supports_pinning = DTraits::supports_pinning; static constexpr size_t device_virtual_bits = DTraits::device_virtual_bits; - static constexpr size_t pin_bits = 32; static constexpr DAddr first_address = 1ULL << Memory::YUZU_PAGEBITS; - static constexpr DAddr max_pin_area = supports_pinning ? 1ULL << pin_bits : first_address; static constexpr DAddr max_device_area = 1ULL << device_virtual_bits; - DeviceMemoryManagerAllocator() - : pin_allocator(first_address), - main_allocator(supports_pinning ? 1ULL << pin_bits : first_address) {} + DeviceMemoryManagerAllocator() : main_allocator(first_address) {} - std::conditional_t, EmptyAllocator> - pin_allocator; Common::FlatAllocator main_allocator; MultiAddressContainer multi_dev_address; /// Returns true when vaddr -> vaddr+size is fully contained in the buffer template [[nodiscard]] bool IsInBounds(VAddr addr, u64 size) const noexcept { - if constexpr (pin_area) { - return addr >= 0 && addr + size <= max_pin_area; - } else { - return addr >= max_pin_area && addr + size <= max_device_area; - } + return addr >= 0 && addr + size <= max_device_area; } DAddr Allocate(size_t size) { return main_allocator.Allocate(size); } - DAddr AllocatePinned(size_t size) { - if constexpr (supports_pinning) { - return pin_allocator.Allocate(size); - } else { - return DAddr{}; - } - } - - void DoInRange(DAddr address, size_t size, auto pin_func, auto main_func) { - if (IsInBounds(address, size)) { - pin_func(address, size); - return; - } - if (IsInBounds(address, size)) { - main_func(address, size); - return; - } - DAddr end_size = address + size - max_pin_area; - DAddr end_size2 = max_pin_area - address; - pin_func(address, end_size2); - main_func(max_pin_area, end_size); - } - void AllocateFixed(DAddr b_address, size_t b_size) { - if constexpr (supports_pinning) { - DoInRange( - b_address, b_size, - [this](DAddr address, size_t size) { pin_allocator.AllocateFixed(address, size); }, - [this](DAddr address, size_t size) { - main_allocator.AllocateFixed(address, size); - }); - } else { - main_allocator.AllocateFixed(b_address, b_size); - } + main_allocator.AllocateFixed(b_address, b_size); } void Free(DAddr b_address, size_t b_size) { - if constexpr (supports_pinning) { - DoInRange( - b_address, b_size, - [this](DAddr address, size_t size) { pin_allocator.Free(address, size); }, - [this](DAddr address, size_t size) { main_allocator.Free(address, size); }); - } else { - main_allocator.Free(b_address, b_size); - } + main_allocator.Free(b_address, b_size); } }; @@ -237,11 +187,6 @@ void DeviceMemoryManager::AllocateFixed(DAddr start, size_t size) { return impl->AllocateFixed(start, size); } -template -DAddr DeviceMemoryManager::AllocatePinned(size_t size) { - return impl->AllocatePinned(size); -} - template void DeviceMemoryManager::Free(DAddr start, size_t size) { impl->Free(start, size); @@ -523,10 +468,10 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS; auto* memory_interface = registered_processes[process_id]; for (; page != page_end; ++page) { - std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page); + std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); if (delta > 0) { - ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits::max(), + ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits::max(), "Count may overflow!"); } else if (delta < 0) { ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); @@ -535,7 +480,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size } // Adds or subtracts 1, as count is a unsigned 8-bit value - count.fetch_add(static_cast(delta), std::memory_order_release); + count.fetch_add(static_cast(delta), std::memory_order_release); // Assume delta is either -1 or 1 if (count.load(std::memory_order::relaxed) == 0) { -- cgit v1.2.3 From d8f1ce2f7640200d92a12698c42029316ac1a611 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 30 Dec 2023 09:37:16 +0100 Subject: SMMU: Add continuity tracking optimization. --- src/core/device_memory_manager.h | 21 ++++++----- src/core/device_memory_manager.inc | 52 +++++++++++++++++++++++++-- src/core/hle/service/nvdrv/core/container.cpp | 1 + src/core/hle/service/nvdrv/core/nvmap.cpp | 2 +- 4 files changed, 63 insertions(+), 13 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index 0273b78db..0f6599cfe 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -13,7 +13,6 @@ #include "common/scratch_buffer.h" #include "common/virtual_buffer.h" - namespace Core { class DeviceMemory; @@ -40,9 +39,17 @@ public: void AllocateFixed(DAddr start, size_t size); void Free(DAddr start, size_t size); - void Map(DAddr address, VAddr virtual_address, size_t size, size_t process_id); + void Map(DAddr address, VAddr virtual_address, size_t size, size_t process_id, + bool track = false); + void Unmap(DAddr address, size_t size); + void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, size_t process_id); + void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, size_t process_id) { + std::scoped_lock lk(mapping_guard); + TrackContinuityImpl(address, virtual_address, size, process_id); + } + // Write / Read template T* GetPointer(DAddr address); @@ -86,13 +93,8 @@ public: template T Read(DAddr address) const; - const u8* GetSpan(const DAddr src_addr, const std::size_t size) const { - return nullptr; - } - - u8* GetSpan(const DAddr src_addr, const std::size_t size) { - return nullptr; - } + u8* GetSpan(const DAddr src_addr, const std::size_t size); + const u8* GetSpan(const DAddr src_addr, const std::size_t size) const; void ReadBlock(DAddr address, void* dest_pointer, size_t size); void ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size); @@ -144,6 +146,7 @@ private: DeviceInterface* interface; Common::VirtualBuffer compressed_physical_ptr; Common::VirtualBuffer compressed_device_addr; + Common::VirtualBuffer continuity_tracker; // Process memory interfaces diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index e9d0efe19..175f0cd5f 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -164,6 +164,7 @@ DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memo : physical_base{reinterpret_cast(device_memory_.buffer.BackingBasePointer())}, interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)), + continuity_tracker(device_as_size >> Memory::YUZU_PAGEBITS), cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) { impl = std::make_unique>(); cached_pages = std::make_unique(); @@ -194,7 +195,7 @@ void DeviceMemoryManager::Free(DAddr start, size_t size) { template void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size_t size, - size_t process_id) { + size_t process_id, bool track) { Core::Memory::Memory* process_memory = registered_processes[process_id]; size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; @@ -222,6 +223,9 @@ void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size } impl->multi_dev_address.Register(new_dev, start_id); } + if (track) { + TrackContinuityImpl(address, virtual_address, size, process_id); + } } template @@ -251,6 +255,47 @@ void DeviceMemoryManager::Unmap(DAddr address, size_t size) { } } } +template +void DeviceMemoryManager::TrackContinuityImpl(DAddr address, VAddr virtual_address, + size_t size, size_t process_id) { + Core::Memory::Memory* process_memory = registered_processes[process_id]; + size_t start_page_d = address >> Memory::YUZU_PAGEBITS; + size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; + uintptr_t last_ptr = 0; + size_t page_count = 1; + for (size_t i = num_pages; i > 0; i--) { + size_t index = i - 1; + const VAddr new_vaddress = virtual_address + index * Memory::YUZU_PAGESIZE; + const uintptr_t new_ptr = reinterpret_cast( + process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress))); + if (new_ptr + page_size == last_ptr) { + page_count++; + } else { + page_count = 1; + } + last_ptr = new_ptr; + continuity_tracker[start_page_d + index] = static_cast(page_count); + } +} +template +u8* DeviceMemoryManager::GetSpan(const DAddr src_addr, const std::size_t size) { + size_t page_index = src_addr >> page_bits; + size_t subbits = src_addr & page_mask; + if ((continuity_tracker[page_index] << page_bits) >= size + subbits) { + return GetPointer(src_addr); + } + return nullptr; +} + +template +const u8* DeviceMemoryManager::GetSpan(const DAddr src_addr, const std::size_t size) const { + size_t page_index = src_addr >> page_bits; + size_t subbits = src_addr & page_mask; + if ((continuity_tracker[page_index] << page_bits) >= size + subbits) { + return GetPointer(src_addr); + } + return nullptr; +} template void DeviceMemoryManager::InnerGatherDeviceAddresses(Common::ScratchBuffer& buffer, @@ -322,12 +367,13 @@ void DeviceMemoryManager::WalkBlock(DAddr addr, std::size_t size, auto o std::size_t page_offset = addr & Memory::YUZU_PAGEMASK; while (remaining_size) { + const size_t next_pages = static_cast(continuity_tracker[page_index]); const std::size_t copy_amount = - std::min(static_cast(Memory::YUZU_PAGESIZE) - page_offset, remaining_size); + std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); const auto current_vaddr = static_cast((page_index << Memory::YUZU_PAGEBITS) + page_offset); SCOPE_EXIT({ - page_index++; + page_index += next_pages; page_offset = 0; increment(copy_amount); remaining_size -= copy_amount; diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index ba7eb9e24..4d3a9d696 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -95,6 +95,7 @@ size_t Container::OpenSession(Kernel::KProcess* process) { if (start_region != 0) { session.mapper = std::make_unique(region_start, start_region, region_size, smmu_id, impl->host1x); + smmu.TrackContinuity(start_region, region_start, region_size, smmu_id); session.has_preallocated_area = true; LOG_CRITICAL(Debug, "Preallocation created!"); } diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 023c070d9..97634b59d 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -221,7 +221,7 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are } handle_description->d_address = address; - smmu.Map(address, vaddress, map_size, session->smmu_id); + smmu.Map(address, vaddress, map_size, session->smmu_id, true); handle_description->in_heap = false; } } -- cgit v1.2.3 From b0bca0f8b04de630f9dec47cff14a640d40f65db Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 30 Dec 2023 23:08:55 +0100 Subject: SMMU: Fix software rendering and cleanup --- src/core/hle/service/nvdrv/core/nvmap.cpp | 8 +++--- src/core/hle/service/nvdrv/core/nvmap.h | 4 +-- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 29 ++++++++-------------- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 7 +++--- .../service/nvdrv/devices/nvhost_nvdec_common.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvmap.cpp | 2 +- .../hle/service/nvnflinger/ui/graphic_buffer.cpp | 2 ++ 7 files changed, 24 insertions(+), 30 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 97634b59d..296b4d8d2 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -22,7 +22,7 @@ NvMap::Handle::Handle(u64 size_, Id id_) flags.raw = 0; } -NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { +NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t pSessionId) { std::scoped_lock lock(mutex); // Handles cannot be allocated twice if (allocated) { @@ -32,6 +32,7 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) flags = pFlags; kind = pKind; align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign; + session_id = pSessionId; // This flag is only applicable for handles with an address passed if (pAddress) { @@ -154,7 +155,7 @@ DAddr NvMap::GetHandleAddress(Handle::Id handle) { } } -DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_area_pin) { +DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) { auto handle_description{GetHandle(handle)}; if (!handle_description) [[unlikely]] { return 0; @@ -198,10 +199,9 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_are // If not then allocate some space and map it DAddr address{}; auto& smmu = host1x.MemoryManager(); - auto* session = core.GetSession(session_id); + auto* session = core.GetSession(handle_description->session_id); const VAddr vaddress = handle_description->address; const size_t map_size = handle_description->aligned_size; - handle_description->session_id = session_id; if (session->has_preallocated_area && session->mapper->IsInBounds(vaddress, map_size)) { handle_description->d_address = session->mapper->Map(vaddress, map_size); handle_description->in_heap = true; diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 4af61289e..119efc38d 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -82,7 +82,7 @@ public: * @brief Sets up the handle with the given memory config, can allocate memory from the tmem * if a 0 address is passed */ - [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress); + [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t pSessionId); /** * @brief Increases the dupe counter of the handle for the given session @@ -130,7 +130,7 @@ public: * number of calls to `UnpinHandle` * @return The SMMU virtual address that the handle has been mapped to */ - DAddr PinHandle(Handle::Id handle, size_t session_id, bool low_area_pin); + DAddr PinHandle(Handle::Id handle, bool low_area_pin); /** * @brief When this has been called an equal number of times to `PinHandle` for the supplied 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 8bc10eac2..936b93bd9 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -40,15 +40,15 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span i case 0x3: return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output); case 0x5: - return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output, fd); + return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output); case 0x6: - return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output, fd); + return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output); case 0x8: return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output); case 0x9: return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output); case 0x14: - return WrapVariable(this, &nvhost_as_gpu::Remap, input, output, fd); + return WrapVariable(this, &nvhost_as_gpu::Remap, input, output); default: break; } @@ -86,15 +86,8 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span i return NvResult::NotImplemented; } -void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) { - sessions[fd] = session_id; -} -void nvhost_as_gpu::OnClose(DeviceFD fd) { - auto it = sessions.find(fd); - if (it != sessions.end()) { - sessions.erase(it); - } -} +void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {} +void nvhost_as_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); @@ -268,7 +261,7 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) { return NvResult::Success; } -NvResult nvhost_as_gpu::Remap(std::span entries, DeviceFD fd) { +NvResult nvhost_as_gpu::Remap(std::span entries) { LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size()); if (!vm.initialised) { @@ -302,7 +295,7 @@ NvResult nvhost_as_gpu::Remap(std::span entries, DeviceFD fd) { return NvResult::BadValue; } - DAddr base = nvmap.PinHandle(entry.handle, sessions[fd], false); + DAddr base = nvmap.PinHandle(entry.handle, false); DAddr device_address{static_cast( base + (static_cast(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; @@ -314,7 +307,7 @@ NvResult nvhost_as_gpu::Remap(std::span entries, DeviceFD fd) { return NvResult::Success; } -NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd) { +NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { LOG_DEBUG(Service_NVDRV, "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" ", offset={}", @@ -358,8 +351,8 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd) { return NvResult::BadValue; } - DAddr device_address{static_cast(nvmap.PinHandle(params.handle, sessions[fd], false) + - params.buffer_offset)}; + DAddr device_address{ + static_cast(nvmap.PinHandle(params.handle, false) + params.buffer_offset)}; u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; bool big_page{[&]() { @@ -414,7 +407,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd) { return NvResult::Success; } -NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params, DeviceFD fd) { +NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); std::scoped_lock lock(mutex); 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 4b28f5078..7fd704bce 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -141,9 +141,9 @@ private: NvResult AllocAsEx(IoctlAllocAsEx& params); NvResult AllocateSpace(IoctlAllocSpace& params); - NvResult Remap(std::span params, DeviceFD fd); - NvResult MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd); - NvResult UnmapBuffer(IoctlUnmapBuffer& params, DeviceFD fd); + NvResult Remap(std::span params); + NvResult MapBufferEx(IoctlMapBufferEx& params); + NvResult UnmapBuffer(IoctlUnmapBuffer& params); NvResult FreeSpace(IoctlFreeSpace& params); NvResult BindChannel(IoctlBindChannel& params); @@ -214,7 +214,6 @@ private: bool initialised{}; } vm; std::shared_ptr gmmu; - std::unordered_map sessions; }; } // namespace Service::Nvidia::Devices 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 a50577c75..a0a7bfa40 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -140,7 +140,7 @@ NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span(entries.size())); for (size_t i = 0; i < num_entries; i++) { - DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd], true); + DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, true); entries[i].map_address = static_cast(pin_address); } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 7765ca1be..24f49ddcd 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -124,7 +124,7 @@ NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) { } const auto result = - handle_description->Alloc(params.flags, params.align, params.kind, params.address); + handle_description->Alloc(params.flags, params.align, params.kind, params.address, sessions[fd]); if (result != NvResult::Success) { LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); return result; diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp index ce70946ec..ede2a1193 100644 --- a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp +++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp @@ -22,11 +22,13 @@ GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap, : NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) { if (this->BufferId() > 0) { m_nvmap->DuplicateHandle(this->BufferId(), true); + m_nvmap->PinHandle(this->BufferId(), false); } } GraphicBuffer::~GraphicBuffer() { if (m_nvmap != nullptr && this->BufferId() > 0) { + m_nvmap->UnpinHandle(this->BufferId()); m_nvmap->FreeHandle(this->BufferId(), true); } } -- cgit v1.2.3 From 590d9b7e1d875e0403fb87cfcd4a8d52c50e2b81 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 31 Dec 2023 20:55:15 +0100 Subject: Core: Clang format and other small issues. --- src/core/device_memory_manager.h | 7 +-- src/core/device_memory_manager.inc | 50 +++++++++++++++------- src/core/guest_memory.h | 5 ++- src/core/hle/service/hle_ipc.cpp | 2 +- src/core/hle/service/nvdrv/core/container.cpp | 8 +++- src/core/hle/service/nvdrv/core/container.h | 8 ++++ src/core/hle/service/nvdrv/core/heap_mapper.cpp | 25 ++++++----- src/core/hle/service/nvdrv/core/nvmap.cpp | 8 ++-- src/core/hle/service/nvdrv/core/nvmap.h | 11 ++--- .../service/nvdrv/devices/nvhost_nvdec_common.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvmap.cpp | 4 +- .../service/nvnflinger/fb_share_buffer_manager.cpp | 10 +++-- .../service/nvnflinger/fb_share_buffer_manager.h | 3 +- src/core/memory.h | 2 +- 15 files changed, 95 insertions(+), 52 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index 0f6599cfe..f9cb13a7a 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -27,13 +27,13 @@ struct DeviceMemoryManagerAllocator; template class DeviceMemoryManager { using DeviceInterface = typename Traits::DeviceInterface; - using DeviceMethods = Traits::DeviceMethods; + using DeviceMethods = typename Traits::DeviceMethods; public: DeviceMemoryManager(const DeviceMemory& device_memory); ~DeviceMemoryManager(); - void BindInterface(DeviceInterface* interface); + void BindInterface(DeviceInterface* device_inter); DAddr Allocate(size_t size); void AllocateFixed(DAddr start, size_t size); @@ -111,6 +111,7 @@ public: private: static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; static constexpr size_t device_as_size = 1ULL << device_virtual_bits; + static constexpr size_t physical_min_bits = 32; static constexpr size_t physical_max_bits = 33; static constexpr size_t page_bits = 12; static constexpr size_t page_size = 1ULL << page_bits; @@ -143,7 +144,7 @@ private: std::unique_ptr> impl; const uintptr_t physical_base; - DeviceInterface* interface; + DeviceInterface* device_inter; Common::VirtualBuffer compressed_physical_ptr; Common::VirtualBuffer compressed_device_addr; Common::VirtualBuffer continuity_tracker; diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 175f0cd5f..a0eb4214e 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -12,6 +12,7 @@ #include "common/assert.h" #include "common/div_ceil.h" #include "common/scope_exit.h" +#include "common/settings.h" #include "core/device_memory.h" #include "core/device_memory_manager.h" #include "core/memory.h" @@ -162,20 +163,39 @@ struct DeviceMemoryManagerAllocator { template DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memory_) : physical_base{reinterpret_cast(device_memory_.buffer.BackingBasePointer())}, - interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), - compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)), + device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), + compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == + Settings::MemoryLayout::Memory_4Gb + ? physical_min_bits + : physical_max_bits) - + Memory::YUZU_PAGEBITS)), continuity_tracker(device_as_size >> Memory::YUZU_PAGEBITS), cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) { impl = std::make_unique>(); cached_pages = std::make_unique(); + + const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS; + for (size_t i = 0; i < total_virtual; i++) { + compressed_physical_ptr[i] = 0; + continuity_tracker[i] = 1; + cpu_backing_address[i] = 0; + } + const size_t total_phys = 1ULL << ((Settings::values.memory_layout_mode.GetValue() == + Settings::MemoryLayout::Memory_4Gb + ? physical_min_bits + : physical_max_bits) - + Memory::YUZU_PAGEBITS); + for (size_t i = 0; i < total_phys; i++) { + compressed_device_addr[i] = 0; + } } template DeviceMemoryManager::~DeviceMemoryManager() = default; template -void DeviceMemoryManager::BindInterface(DeviceInterface* interface_) { - interface = interface_; +void DeviceMemoryManager::BindInterface(DeviceInterface* device_inter_) { + device_inter = device_inter_; } template @@ -232,7 +252,7 @@ template void DeviceMemoryManager::Unmap(DAddr address, size_t size) { size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; - interface->InvalidateRegion(address, size); + device_inter->InvalidateRegion(address, size); std::scoped_lock lk(mapping_guard); for (size_t i = 0; i < num_pages; i++) { auto phys_addr = compressed_physical_ptr[start_page_d + i]; @@ -392,7 +412,7 @@ void DeviceMemoryManager::WalkBlock(DAddr addr, std::size_t size, auto o template void DeviceMemoryManager::ReadBlock(DAddr address, void* dest_pointer, size_t size) { - interface->FlushRegion(address, size); + device_inter->FlushRegion(address, size); WalkBlock( address, size, [&](size_t copy_amount, DAddr current_vaddr) { @@ -426,7 +446,7 @@ void DeviceMemoryManager::WriteBlock(DAddr address, const void* src_poin [&](const std::size_t copy_amount) { src_pointer = static_cast(src_pointer) + copy_amount; }); - interface->InvalidateRegion(address, size); + device_inter->InvalidateRegion(address, size); } template @@ -468,14 +488,14 @@ void DeviceMemoryManager::WriteBlockUnsafe(DAddr address, const void* sr } template -size_t DeviceMemoryManager::RegisterProcess(Memory::Memory* memory_interface) { +size_t DeviceMemoryManager::RegisterProcess(Memory::Memory* memory_device_inter) { size_t new_id; if (!id_pool.empty()) { new_id = id_pool.front(); id_pool.pop_front(); - registered_processes[new_id] = memory_interface; + registered_processes[new_id] = memory_device_inter; } else { - registered_processes.emplace_back(memory_interface); + registered_processes.emplace_back(memory_device_inter); new_id = registered_processes.size() - 1U; } return new_id; @@ -512,7 +532,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size size_t page = addr >> Memory::YUZU_PAGEBITS; auto [process_id, base_vaddress] = ExtractCPUBacking(page); size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS; - auto* memory_interface = registered_processes[process_id]; + auto* memory_device_inter = registered_processes[process_id]; for (; page != page_end; ++page) { std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); @@ -536,7 +556,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size uncache_bytes += Memory::YUZU_PAGESIZE; } else if (uncache_bytes > 0) { lock(); - MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, + MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); uncache_bytes = 0; } @@ -547,7 +567,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size cache_bytes += Memory::YUZU_PAGESIZE; } else if (cache_bytes > 0) { lock(); - MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, + MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, true); cache_bytes = 0; } @@ -555,12 +575,12 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size } if (uncache_bytes > 0) { lock(); - MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, + MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); } if (cache_bytes > 0) { lock(); - MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, + MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, true); } } diff --git a/src/core/guest_memory.h b/src/core/guest_memory.h index 0b349cc17..8030df73a 100644 --- a/src/core/guest_memory.h +++ b/src/core/guest_memory.h @@ -202,7 +202,8 @@ public: } else { this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes()); } - } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || (FLAGS & GuestMemoryFlags::Cached)) { + } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || + (FLAGS & GuestMemoryFlags::Cached)) { this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes()); } } @@ -215,4 +216,4 @@ using CpuGuestMemory = GuestMemory; template using CpuGuestMemoryScoped = GuestMemoryScoped; -} // namespace Tegra::Memory +} // namespace Core::Memory diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 9f6274c7d..e491dd260 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -12,6 +12,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/scratch_buffer.h" +#include "core/guest_memory.h" #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_process.h" @@ -22,7 +23,6 @@ #include "core/hle/service/hle_ipc.h" #include "core/hle/service/ipc_helpers.h" #include "core/memory.h" -#include "core/guest_memory.h" namespace Service { diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index 4d3a9d696..d04b7f5ff 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -16,6 +16,12 @@ namespace Service::Nvidia::NvCore { +Session::Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_) + : id{id_}, process{process_}, smmu_id{smmu_id_}, + has_preallocated_area{}, mapper{}, is_active{} {} + +Session::~Session() = default; + struct ContainerImpl { explicit ContainerImpl(Container& core, Tegra::Host1x::Host1x& host1x_) : host1x{host1x_}, file{core, host1x_}, manager{host1x_}, device_file_data{} {} @@ -54,8 +60,8 @@ size_t Container::OpenSession(Kernel::KProcess* process) { impl->id_pool.pop_front(); impl->sessions[new_id] = Session{new_id, process, smmu_id}; } else { - impl->sessions.emplace_back(new_id, process, smmu_id); new_id = impl->new_ids++; + impl->sessions.emplace_back(new_id, process, smmu_id); } auto& session = impl->sessions[new_id]; session.is_active = true; diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index 86705cbc8..4b8452844 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -27,6 +27,14 @@ class SyncpointManager; struct ContainerImpl; struct Session { + Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_); + ~Session(); + + Session(const Session&) = delete; + Session& operator=(const Session&) = delete; + Session(Session&&) = default; + Session& operator=(Session&&) = default; + size_t id; Kernel::KProcess* process; size_t smmu_id; diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.cpp b/src/core/hle/service/nvdrv/core/heap_mapper.cpp index 59d993bc6..c29191b92 100644 --- a/src/core/hle/service/nvdrv/core/heap_mapper.cpp +++ b/src/core/hle/service/nvdrv/core/heap_mapper.cpp @@ -124,10 +124,11 @@ DAddr HeapMapper::Map(VAddr start, size_t size) { m_internal->base_set.clear(); const IntervalType interval{start, start + size}; m_internal->base_set.insert(interval); - m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, [this](VAddr start_addr, VAddr end_addr, int){ - const IntervalType other{start_addr, end_addr}; - m_internal->base_set.subtract(other); - }); + m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, + [this](VAddr start_addr, VAddr end_addr, int) { + const IntervalType other{start_addr, end_addr}; + m_internal->base_set.subtract(other); + }); if (!m_internal->base_set.empty()) { auto it = m_internal->base_set.begin(); auto end_it = m_internal->base_set.end(); @@ -136,7 +137,8 @@ DAddr HeapMapper::Map(VAddr start, size_t size) { const VAddr inter_addr = it->lower(); const size_t offset = inter_addr - m_vaddress; const size_t sub_size = inter_addr_end - inter_addr; - m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, m_smmu_id); + m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, + m_smmu_id); } } m_internal->mapping_overlaps += std::make_pair(interval, 1); @@ -147,12 +149,13 @@ DAddr HeapMapper::Map(VAddr start, size_t size) { void HeapMapper::Unmap(VAddr start, size_t size) { std::scoped_lock lk(m_internal->guard); m_internal->base_set.clear(); - m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, [this](VAddr start_addr, VAddr end_addr, int value) { - if (value <= 1) { - const IntervalType other{start_addr, end_addr}; - m_internal->base_set.insert(other); - } - }); + m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, + [this](VAddr start_addr, VAddr end_addr, int value) { + if (value <= 1) { + const IntervalType other{start_addr, end_addr}; + m_internal->base_set.insert(other); + } + }); if (!m_internal->base_set.empty()) { auto it = m_internal->base_set.begin(); auto end_it = m_internal->base_set.end(); diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 296b4d8d2..6e59d4fe1 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -13,8 +13,8 @@ #include "core/memory.h" #include "video_core/host1x/host1x.h" - using Core::Memory::YUZU_PAGESIZE; +constexpr size_t BIG_PAGE_SIZE = YUZU_PAGESIZE * 16; namespace Service::Nvidia::NvCore { NvMap::Handle::Handle(u64 size_, Id id_) @@ -96,8 +96,9 @@ void NvMap::UnmapHandle(Handle& handle_description) { const size_t map_size = handle_description.aligned_size; if (!handle_description.in_heap) { auto& smmu = host1x.MemoryManager(); + size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE); smmu.Unmap(handle_description.d_address, map_size); - smmu.Free(handle_description.d_address, static_cast(map_size)); + smmu.Free(handle_description.d_address, static_cast(aligned_up)); handle_description.d_address = 0; return; } @@ -206,7 +207,8 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) { handle_description->d_address = session->mapper->Map(vaddress, map_size); handle_description->in_heap = true; } else { - while ((address = smmu.Allocate(map_size)) == 0) { + size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE); + while ((address = smmu.Allocate(aligned_up)) == 0) { // Free handles until the allocation succeeds std::scoped_lock queueLock(unmap_queue_lock); if (auto freeHandleDesc{unmap_queue.front()}) { diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index 119efc38d..aa5cd21ec 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -63,8 +63,8 @@ public: } flags{}; static_assert(sizeof(Flags) == sizeof(u32)); - VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, - //!< this can also be in the nvdrv tmem + VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, + //!< this can also be in the nvdrv tmem bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC //!< call @@ -73,8 +73,8 @@ public: bool in_heap{}; size_t session_id{}; - DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, - //!< this can also be in the nvdrv tmem + DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds + //!< to, this can also be in the nvdrv tmem Handle(u64 size, Id id); @@ -82,7 +82,8 @@ public: * @brief Sets up the handle with the given memory config, can allocate memory from the tmem * if a 0 address is passed */ - [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t pSessionId); + [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, + size_t pSessionId); /** * @brief Increases the dupe counter of the handle for the given session 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 b44b17a82..718e0fecd 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -4,8 +4,8 @@ #pragma once #include -#include #include +#include #include "common/common_types.h" #include "common/swap.h" diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index d4c93ea5d..a27bed29b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -69,7 +69,7 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span inpu } void nvhost_vic::OnOpen(size_t session_id, DeviceFD fd) { - sessions[fd] = session_id; + sessions[fd] = session_id; } void nvhost_vic::OnClose(DeviceFD fd) { diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 24f49ddcd..08ee8ec24 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -123,8 +123,8 @@ NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) { return NvResult::InsufficientMemory; } - const auto result = - handle_description->Alloc(params.flags, params.align, params.kind, params.address, sessions[fd]); + const auto result = handle_description->Alloc(params.flags, params.align, params.kind, + params.address, sessions[fd]); if (result != NvResult::Success) { LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); return result; diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index d36eff4ec..86e272b41 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -92,7 +92,8 @@ Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::Device Nvidia::Devices::nvmap::IocFreeParams free_params{ .handle = handle, }; - R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success, VI::ResultOperationFailed); + R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success, + VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); @@ -109,7 +110,8 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce .kind = 0, .address = GetInteger(buffer), }; - R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success, VI::ResultOperationFailed); + R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success, + VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); @@ -201,8 +203,8 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id); // Create an nvmap handle for the buffer and assign the memory to it. - R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd, map_address, - SharedBufferSize)); + R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd, + map_address, SharedBufferSize)); // Record the display id. m_display_id = display_id; diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h index 4b1a3d430..d2ec7a9b9 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h @@ -4,9 +4,9 @@ #pragma once #include "common/math_util.h" +#include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/ui/fence.h" -#include "core/hle/service/nvdrv/nvdata.h" namespace Kernel { class KPageGroup; @@ -62,7 +62,6 @@ private: Core::System& m_system; Nvnflinger& m_flinger; std::shared_ptr m_nvdrv; - }; } // namespace Service::Nvnflinger diff --git a/src/core/memory.h b/src/core/memory.h index 9d29cfd3f..552fd585f 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -488,7 +488,7 @@ public: void SetGPUDirtyManagers(std::span managers); bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); - + bool InvalidateSeparateHeap(void* fault_address); private: -- cgit v1.2.3 From a874ab0133459b713205a87738234fae03dc715b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 5 Jan 2024 03:47:48 +0100 Subject: SMMU: Fix 8Gb layout. --- src/core/device_memory_manager.inc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index a0eb4214e..5241293b6 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -340,8 +340,8 @@ T* DeviceMemoryManager::GetPointer(DAddr address) { if (phys_addr == 0) [[unlikely]] { return nullptr; } - return GetPointerFromRaw( - static_cast(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset)); + return GetPointerFromRaw((static_cast(phys_addr - 1) << Memory::YUZU_PAGEBITS) + + offset); } template @@ -353,8 +353,8 @@ const T* DeviceMemoryManager::GetPointer(DAddr address) const { if (phys_addr == 0) [[unlikely]] { return nullptr; } - return GetPointerFromRaw( - static_cast(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset)); + return GetPointerFromRaw((static_cast(phys_addr - 1) << Memory::YUZU_PAGEBITS) + + offset); } template @@ -405,7 +405,7 @@ void DeviceMemoryManager::WalkBlock(DAddr addr, std::size_t size, auto o continue; } auto* mem_ptr = GetPointerFromRaw( - static_cast(((phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset)); + (static_cast(phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset); on_memory(copy_amount, mem_ptr); } } -- cgit v1.2.3 From 067284733075fb0604dbcdc6238d23cfa27c5355 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 7 Jan 2024 04:50:06 +0100 Subject: SMMU: Fix Right Shift UB. --- src/core/device_memory_manager.h | 4 ++-- src/core/device_memory_manager.inc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index f9cb13a7a..cc9fd023f 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -62,13 +62,13 @@ public: DAddr subbits = static_cast(address & page_mask); const u32 base = compressed_device_addr[(address >> page_bits)]; if ((base >> MULTI_FLAG_BITS) == 0) [[likely]] { - const DAddr d_address = static_cast(base << page_bits) + subbits; + const DAddr d_address = (static_cast(base) << page_bits) + subbits; operation(d_address); return; } InnerGatherDeviceAddresses(buffer, address); for (u32 value : buffer) { - operation(static_cast(value << page_bits) + subbits); + operation((static_cast(value) << page_bits) + subbits); } } diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 5241293b6..d7b4abacc 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -301,7 +301,7 @@ template u8* DeviceMemoryManager::GetSpan(const DAddr src_addr, const std::size_t size) { size_t page_index = src_addr >> page_bits; size_t subbits = src_addr & page_mask; - if ((continuity_tracker[page_index] << page_bits) >= size + subbits) { + if ((static_cast(continuity_tracker[page_index]) << page_bits) >= size + subbits) { return GetPointer(src_addr); } return nullptr; @@ -311,7 +311,7 @@ template const u8* DeviceMemoryManager::GetSpan(const DAddr src_addr, const std::size_t size) const { size_t page_index = src_addr >> page_bits; size_t subbits = src_addr & page_mask; - if ((continuity_tracker[page_index] << page_bits) >= size + subbits) { + if ((static_cast(continuity_tracker[page_index]) << page_bits) >= size + subbits) { return GetPointer(src_addr); } return nullptr; -- cgit v1.2.3 From 23430e67724d803184b6a861e4bcb3cac0e38cb0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 7 Jan 2024 05:33:43 +0100 Subject: Core: Eliminate core/memory dependancies. --- src/core/device_memory_manager.h | 4 ++++ src/core/gpu_dirty_memory_manager.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index cc9fd023f..6311e9ece 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -15,6 +15,10 @@ namespace Core { +constexpr size_t DEVICE_PAGEBITS = 12ULL; +constexpr size_t DEVICE_PAGESIZE = 1ULL << DEVICE_PAGEBITS; +constexpr size_t DEVICE_PAGEMASK = DEVICE_PAGESIZE - 1ULL; + class DeviceMemory; namespace Memory { diff --git a/src/core/gpu_dirty_memory_manager.h b/src/core/gpu_dirty_memory_manager.h index f1abf4f83..cc8fc176f 100644 --- a/src/core/gpu_dirty_memory_manager.h +++ b/src/core/gpu_dirty_memory_manager.h @@ -10,7 +10,7 @@ #include #include -#include "core/memory.h" +#include "core/device_memory_manager.h" namespace Core { @@ -80,7 +80,7 @@ private: u32 mask; }; - constexpr static size_t page_bits = Memory::YUZU_PAGEBITS - 1; + constexpr static size_t page_bits = DEVICE_PAGEBITS - 1; constexpr static size_t page_size = 1ULL << page_bits; constexpr static size_t page_mask = page_size - 1; -- cgit v1.2.3 From 648ed55fe61f4f55f2a8c58d9bc2d4dca934cd37 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 7 Jan 2024 07:52:09 +0100 Subject: Core: Make sure GPU Dirty Managers ae shared by all processes. --- src/core/core.cpp | 12 +++++++++++- src/core/core.h | 4 ++++ src/core/hle/kernel/k_process.cpp | 14 ++++---------- src/core/hle/kernel/k_process.h | 4 ---- 4 files changed, 19 insertions(+), 15 deletions(-) (limited to 'src/core') diff --git a/src/core/core.cpp b/src/core/core.cpp index 04e1f13ff..2392fe136 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -28,6 +28,7 @@ #include "core/file_sys/savedata_factory.h" #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" +#include "core/gpu_dirty_memory_manager.h" #include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_resource_limit.h" @@ -565,6 +566,9 @@ struct System::Impl { std::array dynarmic_ticks{}; std::array microprofile_cpu{}; + std::array + gpu_dirty_memory_managers; + std::deque> user_channel; }; @@ -651,8 +655,14 @@ size_t System::GetCurrentHostThreadID() const { return impl->kernel.GetCurrentHostThreadID(); } +std::span System::GetGPUDirtyMemoryManager() { + return impl->gpu_dirty_memory_managers; +} + void System::GatherGPUDirtyMemory(std::function& callback) { - return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); + for (auto& manager : impl->gpu_dirty_memory_managers) { + manager.Gather(callback); + } } PerfStatsResults System::GetAndResetPerfStats() { diff --git a/src/core/core.h b/src/core/core.h index 20ec2ffff..80446f385 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -116,6 +117,7 @@ class CpuManager; class Debugger; class DeviceMemory; class ExclusiveMonitor; +class GPUDirtyMemoryManager; class PerfStats; class Reporter; class SpeedLimiter; @@ -224,6 +226,8 @@ public: /// Prepare the core emulation for a reschedule void PrepareReschedule(u32 core_index); + std::span GetGPUDirtyMemoryManager(); + void GatherGPUDirtyMemory(std::function& callback); [[nodiscard]] size_t GetCurrentHostThreadID() const; diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 53735a225..0b08e877e 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -5,6 +5,7 @@ #include "common/scope_exit.h" #include "common/settings.h" #include "core/core.h" +#include "core/gpu_dirty_memory_manager.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_shared_memory.h" @@ -320,7 +321,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa // Ensure our memory is initialized. m_memory.SetCurrentPageTable(*this); - m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); + m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager()); // Ensure we can insert the code region. R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, @@ -417,7 +418,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, // Ensure our memory is initialized. m_memory.SetCurrentPageTable(*this); - m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); + m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager()); // Ensure we can insert the code region. R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), @@ -1141,8 +1142,7 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {} KProcess::KProcess(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, - m_handle_table{kernel}, m_dirty_memory_managers{}, - m_exclusive_monitor{}, m_memory{kernel.System()} {} + m_handle_table{kernel}, m_exclusive_monitor{}, m_memory{kernel.System()} {} KProcess::~KProcess() = default; Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, @@ -1324,10 +1324,4 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT return true; } -void KProcess::GatherGPUDirtyMemory(std::function& callback) { - for (auto& manager : m_dirty_memory_managers) { - manager.Gather(callback); - } -} - } // namespace Kernel diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 53c0e3316..ab1358a12 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -7,7 +7,6 @@ #include "core/arm/arm_interface.h" #include "core/file_sys/program_metadata.h" -#include "core/gpu_dirty_memory_manager.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_capabilities.h" @@ -128,7 +127,6 @@ private: #ifdef HAS_NCE std::unordered_map m_post_handlers{}; #endif - std::array m_dirty_memory_managers; std::unique_ptr m_exclusive_monitor; Core::Memory::Memory m_memory; @@ -511,8 +509,6 @@ public: return m_memory; } - void GatherGPUDirtyMemory(std::function& callback); - Core::ExclusiveMonitor& GetExclusiveMonitor() const { return *m_exclusive_monitor; } -- cgit v1.2.3 From 4b963ca8a522ec8eb7198209719925e4077246fe Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 7 Jan 2024 07:56:51 +0100 Subject: Core: Invert guest memory depandancy --- src/core/guest_memory.h | 7 +------ src/core/memory.h | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/core') diff --git a/src/core/guest_memory.h b/src/core/guest_memory.h index 8030df73a..7ee18c126 100644 --- a/src/core/guest_memory.h +++ b/src/core/guest_memory.h @@ -9,8 +9,8 @@ #include #include +#include "common/assert.h" #include "common/scratch_buffer.h" -#include "core/memory.h" namespace Core::Memory { @@ -211,9 +211,4 @@ public: }; } // namespace -template -using CpuGuestMemory = GuestMemory; -template -using CpuGuestMemoryScoped = GuestMemoryScoped; - } // namespace Core::Memory diff --git a/src/core/memory.h b/src/core/memory.h index 552fd585f..f7e6b297f 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -12,6 +12,7 @@ #include "common/scratch_buffer.h" #include "common/typed_address.h" +#include "core/guest_memory.h" #include "core/hle/result.h" namespace Common { @@ -498,4 +499,9 @@ private: std::unique_ptr impl; }; +template +using CpuGuestMemory = GuestMemory; +template +using CpuGuestMemoryScoped = GuestMemoryScoped; + } // namespace Core::Memory -- cgit v1.2.3 From beb438bb0bede8b8906a41f7a1ad7b010ec3ec60 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 15 Jan 2024 21:47:59 -0500 Subject: nvdrv: use static typing for SessionId, smmu Asid types --- src/core/device_memory_manager.h | 31 ++++++++++++---------- src/core/device_memory_manager.inc | 28 +++++++++---------- src/core/hle/service/nvdrv/core/container.cpp | 31 +++++++++++----------- src/core/hle/service/nvdrv/core/container.h | 17 +++++++----- src/core/hle/service/nvdrv/core/heap_mapper.cpp | 8 +++--- src/core/hle/service/nvdrv/core/heap_mapper.h | 7 ++--- src/core/hle/service/nvdrv/core/nvmap.cpp | 5 ++-- src/core/hle/service/nvdrv/core/nvmap.h | 5 ++-- src/core/hle/service/nvdrv/devices/nvdevice.h | 3 ++- .../hle/service/nvdrv/devices/nvdisp_disp0.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvdisp_disp0.h | 2 +- .../hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 2 +- .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 2 +- .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 2 +- .../hle/service/nvdrv/devices/nvhost_nvdec.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 2 +- .../service/nvdrv/devices/nvhost_nvdec_common.h | 2 +- .../hle/service/nvdrv/devices/nvhost_nvjpg.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h | 2 +- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvhost_vic.h | 2 +- src/core/hle/service/nvdrv/devices/nvmap.cpp | 2 +- src/core/hle/service/nvdrv/devices/nvmap.h | 4 +-- src/core/hle/service/nvdrv/nvdrv.cpp | 2 +- src/core/hle/service/nvdrv/nvdrv.h | 2 +- src/core/hle/service/nvdrv/nvdrv_interface.h | 2 +- .../service/nvnflinger/fb_share_buffer_manager.h | 3 ++- src/core/hle/service/nvnflinger/nvnflinger.cpp | 2 +- 33 files changed, 99 insertions(+), 87 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index 6311e9ece..ffeed46cc 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -28,6 +28,10 @@ class Memory; template struct DeviceMemoryManagerAllocator; +struct Asid { + size_t id; +}; + template class DeviceMemoryManager { using DeviceInterface = typename Traits::DeviceInterface; @@ -43,15 +47,14 @@ public: void AllocateFixed(DAddr start, size_t size); void Free(DAddr start, size_t size); - void Map(DAddr address, VAddr virtual_address, size_t size, size_t process_id, - bool track = false); + void Map(DAddr address, VAddr virtual_address, size_t size, Asid asid, bool track = false); void Unmap(DAddr address, size_t size); - void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, size_t process_id); - void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, size_t process_id) { + void TrackContinuityImpl(DAddr address, VAddr virtual_address, size_t size, Asid asid); + void TrackContinuity(DAddr address, VAddr virtual_address, size_t size, Asid asid) { std::scoped_lock lk(mapping_guard); - TrackContinuityImpl(address, virtual_address, size, process_id); + TrackContinuityImpl(address, virtual_address, size, asid); } // Write / Read @@ -105,8 +108,8 @@ public: void WriteBlock(DAddr address, const void* src_pointer, size_t size); void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size); - size_t RegisterProcess(Memory::Memory* memory); - void UnregisterProcess(size_t id); + Asid RegisterProcess(Memory::Memory* memory); + void UnregisterProcess(Asid id); void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta); @@ -163,17 +166,17 @@ private: static constexpr size_t guest_max_as_bits = 39; static constexpr size_t guest_as_size = 1ULL << guest_max_as_bits; static constexpr size_t guest_mask = guest_as_size - 1ULL; - static constexpr size_t process_id_start_bit = guest_max_as_bits; + static constexpr size_t asid_start_bit = guest_max_as_bits; - std::pair ExtractCPUBacking(size_t page_index) { + std::pair ExtractCPUBacking(size_t page_index) { auto content = cpu_backing_address[page_index]; const VAddr address = content & guest_mask; - const size_t process_id = static_cast(content >> process_id_start_bit); - return std::make_pair(process_id, address); + const Asid asid{static_cast(content >> asid_start_bit)}; + return std::make_pair(asid, address); } - void InsertCPUBacking(size_t page_index, VAddr address, size_t process_id) { - cpu_backing_address[page_index] = address | (process_id << process_id_start_bit); + void InsertCPUBacking(size_t page_index, VAddr address, Asid asid) { + cpu_backing_address[page_index] = address | (asid.id << asid_start_bit); } Common::VirtualBuffer cpu_backing_address; @@ -205,4 +208,4 @@ private: std::mutex mapping_guard; }; -} // namespace Core \ No newline at end of file +} // namespace Core diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index d7b4abacc..f6e4ad874 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -215,8 +215,8 @@ void DeviceMemoryManager::Free(DAddr start, size_t size) { template void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size_t size, - size_t process_id, bool track) { - Core::Memory::Memory* process_memory = registered_processes[process_id]; + Asid asid, bool track) { + Core::Memory::Memory* process_memory = registered_processes[asid.id]; size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; std::scoped_lock lk(mapping_guard); @@ -229,7 +229,7 @@ void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size } auto phys_addr = static_cast(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U; compressed_physical_ptr[start_page_d + i] = phys_addr; - InsertCPUBacking(start_page_d + i, new_vaddress, process_id); + InsertCPUBacking(start_page_d + i, new_vaddress, asid); const u32 base_dev = compressed_device_addr[phys_addr - 1U]; const u32 new_dev = static_cast(start_page_d + i); if (base_dev == 0) [[likely]] { @@ -244,7 +244,7 @@ void DeviceMemoryManager::Map(DAddr address, VAddr virtual_address, size impl->multi_dev_address.Register(new_dev, start_id); } if (track) { - TrackContinuityImpl(address, virtual_address, size, process_id); + TrackContinuityImpl(address, virtual_address, size, asid); } } @@ -277,8 +277,8 @@ void DeviceMemoryManager::Unmap(DAddr address, size_t size) { } template void DeviceMemoryManager::TrackContinuityImpl(DAddr address, VAddr virtual_address, - size_t size, size_t process_id) { - Core::Memory::Memory* process_memory = registered_processes[process_id]; + size_t size, Asid asid) { + Core::Memory::Memory* process_memory = registered_processes[asid.id]; size_t start_page_d = address >> Memory::YUZU_PAGEBITS; size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; uintptr_t last_ptr = 0; @@ -488,8 +488,8 @@ void DeviceMemoryManager::WriteBlockUnsafe(DAddr address, const void* sr } template -size_t DeviceMemoryManager::RegisterProcess(Memory::Memory* memory_device_inter) { - size_t new_id; +Asid DeviceMemoryManager::RegisterProcess(Memory::Memory* memory_device_inter) { + size_t new_id{}; if (!id_pool.empty()) { new_id = id_pool.front(); id_pool.pop_front(); @@ -498,13 +498,13 @@ size_t DeviceMemoryManager::RegisterProcess(Memory::Memory* memory_devic registered_processes.emplace_back(memory_device_inter); new_id = registered_processes.size() - 1U; } - return new_id; + return Asid{new_id}; } template -void DeviceMemoryManager::UnregisterProcess(size_t id) { - registered_processes[id] = nullptr; - id_pool.push_front(id); +void DeviceMemoryManager::UnregisterProcess(Asid asid) { + registered_processes[asid.id] = nullptr; + id_pool.push_front(asid.id); } template @@ -530,9 +530,9 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size std::atomic_thread_fence(std::memory_order_acquire); const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); size_t page = addr >> Memory::YUZU_PAGEBITS; - auto [process_id, base_vaddress] = ExtractCPUBacking(page); + auto [asid, base_vaddress] = ExtractCPUBacking(page); size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS; - auto* memory_device_inter = registered_processes[process_id]; + auto* memory_device_inter = registered_processes[asid.id]; for (; page != page_end; ++page) { std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index d04b7f5ff..b5fd98a9d 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -16,9 +16,8 @@ namespace Service::Nvidia::NvCore { -Session::Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_) - : id{id_}, process{process_}, smmu_id{smmu_id_}, - has_preallocated_area{}, mapper{}, is_active{} {} +Session::Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_) + : id{id_}, process{process_}, asid{asid_}, has_preallocated_area{}, mapper{}, is_active{} {} Session::~Session() = default; @@ -41,7 +40,7 @@ Container::Container(Tegra::Host1x::Host1x& host1x_) { Container::~Container() = default; -size_t Container::OpenSession(Kernel::KProcess* process) { +SessionId Container::OpenSession(Kernel::KProcess* process) { std::scoped_lock lk(impl->session_guard); for (auto& session : impl->sessions) { if (!session.is_active) { @@ -54,14 +53,14 @@ size_t Container::OpenSession(Kernel::KProcess* process) { size_t new_id{}; auto* memory_interface = &process->GetMemory(); auto& smmu = impl->host1x.MemoryManager(); - auto smmu_id = smmu.RegisterProcess(memory_interface); + auto asid = smmu.RegisterProcess(memory_interface); if (!impl->id_pool.empty()) { new_id = impl->id_pool.front(); impl->id_pool.pop_front(); - impl->sessions[new_id] = Session{new_id, process, smmu_id}; + impl->sessions[new_id] = Session{SessionId{new_id}, process, asid}; } else { new_id = impl->new_ids++; - impl->sessions.emplace_back(new_id, process, smmu_id); + impl->sessions.emplace_back(SessionId{new_id}, process, asid); } auto& session = impl->sessions[new_id]; session.is_active = true; @@ -100,18 +99,18 @@ size_t Container::OpenSession(Kernel::KProcess* process) { auto start_region = (region_size >> 15) >= 1024 ? smmu.Allocate(region_size) : 0; if (start_region != 0) { session.mapper = std::make_unique(region_start, start_region, region_size, - smmu_id, impl->host1x); - smmu.TrackContinuity(start_region, region_start, region_size, smmu_id); + asid, impl->host1x); + smmu.TrackContinuity(start_region, region_start, region_size, asid); session.has_preallocated_area = true; LOG_CRITICAL(Debug, "Preallocation created!"); } } - return new_id; + return SessionId{new_id}; } -void Container::CloseSession(size_t id) { +void Container::CloseSession(SessionId session_id) { std::scoped_lock lk(impl->session_guard); - auto& session = impl->sessions[id]; + auto& session = impl->sessions[session_id.id]; auto& smmu = impl->host1x.MemoryManager(); if (session.has_preallocated_area) { const DAddr region_start = session.mapper->GetRegionStart(); @@ -121,13 +120,13 @@ void Container::CloseSession(size_t id) { session.has_preallocated_area = false; } session.is_active = false; - smmu.UnregisterProcess(impl->sessions[id].smmu_id); - impl->id_pool.emplace_front(id); + smmu.UnregisterProcess(impl->sessions[session_id.id].asid); + impl->id_pool.emplace_front(session_id.id); } -Session* Container::GetSession(size_t id) { +Session* Container::GetSession(SessionId session_id) { std::atomic_thread_fence(std::memory_order_acquire); - return &impl->sessions[id]; + return &impl->sessions[session_id.id]; } NvMap& Container::GetNvMapFile() { diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index 4b8452844..b4d3938a8 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -8,6 +8,7 @@ #include #include +#include "core/device_memory_manager.h" #include "core/hle/service/nvdrv/nvdata.h" namespace Kernel { @@ -26,8 +27,12 @@ class SyncpointManager; struct ContainerImpl; +struct SessionId { + size_t id; +}; + struct Session { - Session(size_t id_, Kernel::KProcess* process_, size_t smmu_id_); + Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_); ~Session(); Session(const Session&) = delete; @@ -35,9 +40,9 @@ struct Session { Session(Session&&) = default; Session& operator=(Session&&) = default; - size_t id; + SessionId id; Kernel::KProcess* process; - size_t smmu_id; + Core::Asid asid; bool has_preallocated_area{}; std::unique_ptr mapper{}; bool is_active{}; @@ -48,10 +53,10 @@ public: explicit Container(Tegra::Host1x::Host1x& host1x); ~Container(); - size_t OpenSession(Kernel::KProcess* process); - void CloseSession(size_t id); + SessionId OpenSession(Kernel::KProcess* process); + void CloseSession(SessionId id); - Session* GetSession(size_t id); + Session* GetSession(SessionId id); NvMap& GetNvMapFile(); diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.cpp b/src/core/hle/service/nvdrv/core/heap_mapper.cpp index c29191b92..096dc5deb 100644 --- a/src/core/hle/service/nvdrv/core/heap_mapper.cpp +++ b/src/core/hle/service/nvdrv/core/heap_mapper.cpp @@ -109,9 +109,9 @@ struct HeapMapper::HeapMapperInternal { std::mutex guard; }; -HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id, +HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid, Tegra::Host1x::Host1x& host1x) - : m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_smmu_id{smmu_id} { + : m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_asid{asid} { m_internal = std::make_unique(host1x); } @@ -138,7 +138,7 @@ DAddr HeapMapper::Map(VAddr start, size_t size) { const size_t offset = inter_addr - m_vaddress; const size_t sub_size = inter_addr_end - inter_addr; m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, - m_smmu_id); + m_asid); } } m_internal->mapping_overlaps += std::make_pair(interval, 1); @@ -172,4 +172,4 @@ void HeapMapper::Unmap(VAddr start, size_t size) { m_internal->base_set.clear(); } -} // namespace Service::Nvidia::NvCore \ No newline at end of file +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.h b/src/core/hle/service/nvdrv/core/heap_mapper.h index 8b23638b8..491a12e4f 100644 --- a/src/core/hle/service/nvdrv/core/heap_mapper.h +++ b/src/core/hle/service/nvdrv/core/heap_mapper.h @@ -6,6 +6,7 @@ #include #include "common/common_types.h" +#include "core/device_memory_manager.h" namespace Tegra::Host1x { class Host1x; @@ -15,7 +16,7 @@ namespace Service::Nvidia::NvCore { class HeapMapper { public: - HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, size_t smmu_id, + HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid, Tegra::Host1x::Host1x& host1x); ~HeapMapper(); @@ -41,8 +42,8 @@ private: VAddr m_vaddress; DAddr m_daddress; size_t m_size; - size_t m_smmu_id; + Core::Asid m_asid; std::unique_ptr m_internal; }; -} // namespace Service::Nvidia::NvCore \ No newline at end of file +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 6e59d4fe1..1b59c6b15 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -22,7 +22,8 @@ NvMap::Handle::Handle(u64 size_, Id id_) flags.raw = 0; } -NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t pSessionId) { +NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, + NvCore::SessionId pSessionId) { std::scoped_lock lock(mutex); // Handles cannot be allocated twice if (allocated) { @@ -223,7 +224,7 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) { } handle_description->d_address = address; - smmu.Map(address, vaddress, map_size, session->smmu_id, true); + smmu.Map(address, vaddress, map_size, session->asid, true); handle_description->in_heap = false; } } diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index aa5cd21ec..d7f695845 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -14,6 +14,7 @@ #include "common/bit_field.h" #include "common/common_types.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" namespace Tegra { @@ -71,7 +72,7 @@ public: u8 kind{}; //!< Used for memory compression bool allocated{}; //!< If the handle has been allocated with `Alloc` bool in_heap{}; - size_t session_id{}; + NvCore::SessionId session_id{}; DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds //!< to, this can also be in the nvdrv tmem @@ -83,7 +84,7 @@ public: * if a 0 address is passed */ [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, - size_t pSessionId); + NvCore::SessionId pSessionId); /** * @brief Increases the dupe counter of the handle for the given session diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index ff91aabcb..8adaddc60 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -7,6 +7,7 @@ #include #include "common/common_types.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" namespace Core { @@ -62,7 +63,7 @@ public: * Called once a device is opened * @param fd The device fd */ - virtual void OnOpen(size_t session_id, DeviceFD fd) = 0; + virtual void OnOpen(NvCore::SessionId session_id, DeviceFD fd) = 0; /** * Called once a device is closed diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index f1404b9da..c1ebbd62d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -35,7 +35,7 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span in return NvResult::NotImplemented; } -void nvdisp_disp0::OnOpen(size_t session_id, DeviceFD fd) {} +void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvdisp_disp0::OnClose(DeviceFD fd) {} void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index 4e32ec191..5f13a50a2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -32,7 +32,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; /// Performs a screen flip, drawing the buffer pointed to by the handle. 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 936b93bd9..e6646ba04 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -86,7 +86,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span i return NvResult::NotImplemented; } -void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {} +void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { 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 7fd704bce..7d0a99988 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -55,7 +55,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index c4033cf1b..250d01de3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -76,7 +76,7 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span inp return NvResult::NotImplemented; } -void nvhost_ctrl::OnOpen(size_t session_id, DeviceFD fd) {} +void nvhost_ctrl::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_ctrl::OnClose(DeviceFD fd) {} diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 84f419f16..403f1a746 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -32,7 +32,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 75276c37c..ddd85678b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span return NvResult::NotImplemented; } -void nvhost_ctrl_gpu::OnOpen(size_t session_id, DeviceFD fd) {} +void nvhost_ctrl_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 6147e37cc..d2ab05b21 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -28,7 +28,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 0929c7128..bf12d69a5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -120,7 +120,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span inpu return NvResult::NotImplemented; } -void nvhost_gpu::OnOpen(size_t session_id, DeviceFD fd) {} +void nvhost_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index f5a396c40..e34a978db 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -47,7 +47,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 63228518e..2c0ac2a46 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -68,7 +68,7 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span in return NvResult::NotImplemented; } -void nvhost_nvdec::OnOpen(size_t session_id, DeviceFD fd) { +void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream started"); system.SetNVDECActive(true); sessions[fd] = session_id; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 1fb27b814..627686757 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -20,7 +20,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; }; 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 718e0fecd..900db81d2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -127,7 +127,7 @@ protected: NvCore::NvMap& nvmap; NvCore::ChannelType channel_type; std::array device_syncpoints{}; - std::unordered_map sessions; + std::unordered_map sessions; }; }; // namespace Devices } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 1c88b39ab..f87d53f12 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -44,7 +44,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span in return NvResult::NotImplemented; } -void nvhost_nvjpg::OnOpen(size_t session_id, DeviceFD fd) {} +void nvhost_nvjpg::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_nvjpg::OnClose(DeviceFD fd) {} NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 3e33dffef..def9c254d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -22,7 +22,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; private: diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index a27bed29b..263061f1d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -68,7 +68,7 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span inpu return NvResult::NotImplemented; } -void nvhost_vic::OnOpen(size_t session_id, DeviceFD fd) { +void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { sessions[fd] = session_id; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index d70df0f20..0cc04354a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -19,7 +19,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 08ee8ec24..da61a3bfe 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -67,7 +67,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span input, st return NvResult::NotImplemented; } -void nvmap::OnOpen(size_t session_id, DeviceFD fd) { +void nvmap::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { sessions[fd] = session_id; } void nvmap::OnClose(DeviceFD fd) { diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index ea5df2a9c..d07d85f88 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -33,7 +33,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, std::span inline_output) override; - void OnOpen(size_t session_id, DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; enum class HandleParameterType : u32_le { @@ -115,7 +115,7 @@ private: NvCore::Container& container; NvCore::NvMap& file; - std::unordered_map sessions; + std::unordered_map sessions; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 5191341db..5f093c0d4 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -122,7 +122,7 @@ NvResult Module::VerifyFD(DeviceFD fd) const { return NvResult::Success; } -DeviceFD Module::Open(const std::string& device_name, size_t session_id) { +DeviceFD Module::Open(const std::string& device_name, NvCore::SessionId session_id) { auto it = builders.find(device_name); if (it == builders.end()) { LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index d7648fb15..c594f0e5e 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -77,7 +77,7 @@ public: NvResult VerifyFD(DeviceFD fd) const; /// Opens a device node and returns a file descriptor to it. - DeviceFD Open(const std::string& device_name, size_t session_id); + DeviceFD Open(const std::string& device_name, NvCore::SessionId session_id); /// Sends an ioctl command to the specified file descriptor. NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span input, std::span output); diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index e7237c881..f2195ae1e 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h @@ -35,7 +35,7 @@ private: u64 pid{}; bool is_initialized{}; - size_t session_id{}; + NvCore::SessionId session_id{}; Common::ScratchBuffer output_buffer; Common::ScratchBuffer inline_output_buffer; }; diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h index d2ec7a9b9..033bf4bbe 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h @@ -4,6 +4,7 @@ #pragma once #include "common/math_util.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/ui/fence.h" @@ -55,7 +56,7 @@ private: u32 m_buffer_nvmap_handle = 0; SharedMemoryPoolLayout m_pool_layout = {}; Nvidia::DeviceFD m_nvmap_fd = {}; - size_t m_session_id = {}; + Nvidia::NvCore::SessionId m_session_id = {}; std::unique_ptr m_buffer_page_group; std::mutex m_guard; diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index e4b38ae0b..423b9aef1 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -126,7 +126,7 @@ void Nvnflinger::ShutdownLayers() { void Nvnflinger::SetNVDrvInstance(std::shared_ptr instance) { nvdrv = std::move(instance); - disp_fd = nvdrv->Open("/dev/nvdisp_disp0", 0); + disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); } std::optional Nvnflinger::OpenDisplay(std::string_view name) { -- cgit v1.2.3 From b6c6534c30bf579b7816d57b5cd7b2aaf2d8f7a5 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 15 Jan 2024 21:49:38 -0500 Subject: nvdrv: use correct names for interface factory --- src/core/hle/service/nvdrv/nvdrv.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 5f093c0d4..cb256e5b4 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -52,15 +52,15 @@ void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { return std::make_shared(system, module, "nvdrv:a"); }; const auto NvdrvInterfaceFactoryForSysmodules = [&, module] { - return std::make_shared(system, module, "nvdrv:a"); + return std::make_shared(system, module, "nvdrv:s"); }; - const auto NvdrvInterfaceFactory = [&, module] { + const auto NvdrvInterfaceFactoryForTesting = [&, module] { return std::make_shared(system, module, "nvdrv:t"); }; server_manager->RegisterNamedService("nvdrv", NvdrvInterfaceFactoryForApplication); server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets); server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules); - server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactory); + server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting); server_manager->RegisterNamedService("nvmemp", std::make_shared(system)); nvnflinger.SetNVDrvInstance(module); ServerManager::RunServer(std::move(server_manager)); -- cgit v1.2.3 From 32f623e029666bafe796ca8bf0a8b95bf9684b5f Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 15 Jan 2024 21:52:28 -0500 Subject: nvdrv: clean up preallocation --- src/core/hle/service/nvdrv/core/container.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index b5fd98a9d..21ef57d27 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -41,6 +41,8 @@ Container::Container(Tegra::Host1x::Host1x& host1x_) { Container::~Container() = default; SessionId Container::OpenSession(Kernel::KProcess* process) { + using namespace Common::Literals; + std::scoped_lock lk(impl->session_guard); for (auto& session : impl->sessions) { if (!session.is_active) { @@ -79,7 +81,7 @@ SessionId Container::OpenSession(Kernel::KProcess* process) { cur_addr)); auto svc_mem_info = mem_info.GetSvcMemoryInfo(); - // check if this memory block is heap + // Check if this memory block is heap. if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { if (svc_mem_info.size > region_size) { region_size = svc_mem_info.size; @@ -96,13 +98,13 @@ SessionId Container::OpenSession(Kernel::KProcess* process) { cur_addr = next_address; } session.has_preallocated_area = false; - auto start_region = (region_size >> 15) >= 1024 ? smmu.Allocate(region_size) : 0; + auto start_region = region_size >= 32_MiB ? smmu.Allocate(region_size) : 0; if (start_region != 0) { session.mapper = std::make_unique(region_start, start_region, region_size, asid, impl->host1x); smmu.TrackContinuity(start_region, region_start, region_size, asid); session.has_preallocated_area = true; - LOG_CRITICAL(Debug, "Preallocation created!"); + LOG_DEBUG(Debug, "Preallocation created!"); } } return SessionId{new_id}; -- cgit v1.2.3 From 04867e2456d926364ede540954767cc39c58e464 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 15 Jan 2024 21:53:20 -0500 Subject: nvhost_vic: use map erase by key --- src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 263061f1d..bf090f5eb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -78,10 +78,7 @@ void nvhost_vic::OnClose(DeviceFD fd) { if (iter != host1x_file.fd_to_id.end()) { system.GPU().ClearCdmaInstance(iter->second); } - auto it = sessions.find(fd); - if (it != sessions.end()) { - sessions.erase(it); - } + sessions.erase(fd); } } // namespace Service::Nvidia::Devices -- cgit v1.2.3 From 748465f5a578fcd99f91e0591ac773940172a72e Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 15 Jan 2024 21:56:38 -0500 Subject: device_memory_manager: use unique_lock for update --- src/core/device_memory_manager.inc | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'src/core') diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index f6e4ad874..8ce122872 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -509,18 +509,12 @@ void DeviceMemoryManager::UnregisterProcess(Asid asid) { template void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { - bool locked = false; - auto lock = [&] { - if (!locked) { - counter_guard.lock(); - locked = true; + std::unique_lock lk(counter_guard, std::defer_lock); + const auto Lock = [&] { + if (!lk) { + lk.lock(); } }; - SCOPE_EXIT({ - if (locked) { - counter_guard.unlock(); - } - }); u64 uncache_begin = 0; u64 cache_begin = 0; u64 uncache_bytes = 0; @@ -555,7 +549,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size } uncache_bytes += Memory::YUZU_PAGESIZE; } else if (uncache_bytes > 0) { - lock(); + Lock(); MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); uncache_bytes = 0; @@ -566,7 +560,7 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size } cache_bytes += Memory::YUZU_PAGESIZE; } else if (cache_bytes > 0) { - lock(); + Lock(); MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, true); cache_bytes = 0; @@ -574,12 +568,12 @@ void DeviceMemoryManager::UpdatePagesCachedCount(DAddr addr, size_t size vpage++; } if (uncache_bytes > 0) { - lock(); + Lock(); MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); } if (cache_bytes > 0) { - lock(); + Lock(); MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, true); } -- cgit v1.2.3