diff options
author | liamwhite <liamwhite@users.noreply.github.com> | 2024-01-31 11:22:29 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-31 11:22:29 -0500 |
commit | 22492b68b73b4e8c865c4907cc4609db8cc07afd (patch) | |
tree | 75d356cf8a9d8e4ae93dda3d35647c80bd51c11c /src/core | |
parent | a12a26e19b8b7b804fec3f948ca9a6fff1abb316 (diff) | |
parent | d57165df450e8a2fa811706758fb8ab352f623ae (diff) |
Merge pull request #12869 from FernandoS27/smmu-fixes
SMMU: A set of different fixes.
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/device_memory_manager.h | 18 | ||||
-rw-r--r-- | src/core/device_memory_manager.inc | 63 | ||||
-rw-r--r-- | src/core/hle/service/nvdrv/core/container.cpp | 4 |
3 files changed, 45 insertions, 40 deletions
diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h index ffeed46cc..0568a821b 100644 --- a/src/core/device_memory_manager.h +++ b/src/core/device_memory_manager.h @@ -5,11 +5,13 @@ #include <array> #include <atomic> +#include <bit> #include <deque> #include <memory> #include <mutex> #include "common/common_types.h" +#include "common/range_mutex.h" #include "common/scratch_buffer.h" #include "common/virtual_buffer.h" @@ -180,31 +182,35 @@ private: } Common::VirtualBuffer<VAddr> cpu_backing_address; - static constexpr size_t subentries = 8 / sizeof(u8); + using CounterType = u8; + using CounterAtomicType = std::atomic_uint8_t; + static constexpr size_t subentries = 8 / sizeof(CounterType); static constexpr size_t subentries_mask = subentries - 1; + static constexpr size_t subentries_shift = + std::countr_zero(sizeof(u64)) - std::countr_zero(sizeof(CounterType)); class CounterEntry final { public: CounterEntry() = default; - std::atomic_uint8_t& Count(std::size_t page) { + CounterAtomicType& Count(std::size_t page) { return values[page & subentries_mask]; } - const std::atomic_uint8_t& Count(std::size_t page) const { + const CounterAtomicType& Count(std::size_t page) const { return values[page & subentries_mask]; } private: - std::array<std::atomic_uint8_t, subentries> values{}; + std::array<CounterAtomicType, subentries> values{}; }; - static_assert(sizeof(CounterEntry) == subentries * sizeof(u8), + static_assert(sizeof(CounterEntry) == subentries * sizeof(CounterType), "CounterEntry should be 8 bytes!"); static constexpr size_t num_counter_entries = (1ULL << (device_virtual_bits - page_bits)) / subentries; using CachedPages = std::array<CounterEntry, num_counter_entries>; std::unique_ptr<CachedPages> cached_pages; - std::mutex counter_guard; + Common::RangeMutex counter_guard; std::mutex mapping_guard; }; diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index eab8a2731..b026f4220 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -213,8 +213,8 @@ void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) { } template <typename Traits> -void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, - Asid asid, bool track) { +void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, 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; @@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) { template <typename Traits> void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { - std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); - const auto Lock = [&] { - if (!lk) { - lk.lock(); - } - }; + Common::ScopedRangeLock lk(counter_guard, addr, size); u64 uncache_begin = 0; u64 cache_begin = 0; u64 uncache_bytes = 0; @@ -524,22 +519,36 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); size_t page = addr >> Memory::YUZU_PAGEBITS; auto [asid, base_vaddress] = ExtractCPUBacking(page); - size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS; auto* memory_device_inter = registered_processes[asid.id]; + const auto release_pending = [&] { + if (uncache_bytes > 0) { + MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, + uncache_bytes, false); + uncache_bytes = 0; + } + if (cache_bytes > 0) { + MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, + cache_bytes, true); + cache_bytes = 0; + } + }; for (; page != page_end; ++page) { - std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); + CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page); + auto [asid_2, vpage] = ExtractCPUBacking(page); + vpage >>= Memory::YUZU_PAGEBITS; - if (delta > 0) { - ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::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!"); + if (vpage == 0) [[unlikely]] { + release_pending(); + continue; + } + + if (asid.id != asid_2.id) [[unlikely]] { + release_pending(); + memory_device_inter = registered_processes[asid_2.id]; } // Adds or subtracts 1, as count is a unsigned 8-bit value - count.fetch_add(static_cast<u8>(delta), std::memory_order_release); + count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release); // Assume delta is either -1 or 1 if (count.load(std::memory_order::relaxed) == 0) { @@ -548,7 +557,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size } uncache_bytes += Memory::YUZU_PAGESIZE; } else if (uncache_bytes > 0) { - Lock(); MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, false); uncache_bytes = 0; @@ -559,23 +567,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size } cache_bytes += Memory::YUZU_PAGESIZE; } else if (cache_bytes > 0) { - Lock(); - MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, - true); + MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, + cache_bytes, true); cache_bytes = 0; } - vpage++; - } - if (uncache_bytes > 0) { - Lock(); - MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, - false); - } - if (cache_bytes > 0) { - Lock(); - MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, - true); } + release_pending(); } } // namespace Core diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index dc1b4d5be..e89cca6f2 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -83,7 +83,9 @@ SessionId Container::OpenSession(Kernel::KProcess* process) { // Check if this memory block is heap. if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { - if (svc_mem_info.size > region_size) { + if (region_start + region_size == svc_mem_info.base_address) { + region_size += svc_mem_info.size; + } else if (svc_mem_info.size > region_size) { region_size = svc_mem_info.size; region_start = svc_mem_info.base_address; } |