diff options
| author | 2024-01-31 11:22:29 -0500 | |
|---|---|---|
| committer | 2024-01-31 11:22:29 -0500 | |
| commit | 22492b68b73b4e8c865c4907cc4609db8cc07afd (patch) | |
| tree | 75d356cf8a9d8e4ae93dda3d35647c80bd51c11c /src/core | |
| parent | Merge pull request #12864 from Kelebek1/small_time_fixes (diff) | |
| parent | Device Memory Manager: ensure raster protection only within mapped device add... (diff) | |
| download | yuzu-22492b68b73b4e8c865c4907cc4609db8cc07afd.tar.gz yuzu-22492b68b73b4e8c865c4907cc4609db8cc07afd.tar.xz yuzu-22492b68b73b4e8c865c4907cc4609db8cc07afd.zip | |
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 @@ | |||
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <bit> | ||
| 8 | #include <deque> | 9 | #include <deque> |
| 9 | #include <memory> | 10 | #include <memory> |
| 10 | #include <mutex> | 11 | #include <mutex> |
| 11 | 12 | ||
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/range_mutex.h" | ||
| 13 | #include "common/scratch_buffer.h" | 15 | #include "common/scratch_buffer.h" |
| 14 | #include "common/virtual_buffer.h" | 16 | #include "common/virtual_buffer.h" |
| 15 | 17 | ||
| @@ -180,31 +182,35 @@ private: | |||
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | Common::VirtualBuffer<VAddr> cpu_backing_address; | 184 | Common::VirtualBuffer<VAddr> cpu_backing_address; |
| 183 | static constexpr size_t subentries = 8 / sizeof(u8); | 185 | using CounterType = u8; |
| 186 | using CounterAtomicType = std::atomic_uint8_t; | ||
| 187 | static constexpr size_t subentries = 8 / sizeof(CounterType); | ||
| 184 | static constexpr size_t subentries_mask = subentries - 1; | 188 | static constexpr size_t subentries_mask = subentries - 1; |
| 189 | static constexpr size_t subentries_shift = | ||
| 190 | std::countr_zero(sizeof(u64)) - std::countr_zero(sizeof(CounterType)); | ||
| 185 | class CounterEntry final { | 191 | class CounterEntry final { |
| 186 | public: | 192 | public: |
| 187 | CounterEntry() = default; | 193 | CounterEntry() = default; |
| 188 | 194 | ||
| 189 | std::atomic_uint8_t& Count(std::size_t page) { | 195 | CounterAtomicType& Count(std::size_t page) { |
| 190 | return values[page & subentries_mask]; | 196 | return values[page & subentries_mask]; |
| 191 | } | 197 | } |
| 192 | 198 | ||
| 193 | const std::atomic_uint8_t& Count(std::size_t page) const { | 199 | const CounterAtomicType& Count(std::size_t page) const { |
| 194 | return values[page & subentries_mask]; | 200 | return values[page & subentries_mask]; |
| 195 | } | 201 | } |
| 196 | 202 | ||
| 197 | private: | 203 | private: |
| 198 | std::array<std::atomic_uint8_t, subentries> values{}; | 204 | std::array<CounterAtomicType, subentries> values{}; |
| 199 | }; | 205 | }; |
| 200 | static_assert(sizeof(CounterEntry) == subentries * sizeof(u8), | 206 | static_assert(sizeof(CounterEntry) == subentries * sizeof(CounterType), |
| 201 | "CounterEntry should be 8 bytes!"); | 207 | "CounterEntry should be 8 bytes!"); |
| 202 | 208 | ||
| 203 | static constexpr size_t num_counter_entries = | 209 | static constexpr size_t num_counter_entries = |
| 204 | (1ULL << (device_virtual_bits - page_bits)) / subentries; | 210 | (1ULL << (device_virtual_bits - page_bits)) / subentries; |
| 205 | using CachedPages = std::array<CounterEntry, num_counter_entries>; | 211 | using CachedPages = std::array<CounterEntry, num_counter_entries>; |
| 206 | std::unique_ptr<CachedPages> cached_pages; | 212 | std::unique_ptr<CachedPages> cached_pages; |
| 207 | std::mutex counter_guard; | 213 | Common::RangeMutex counter_guard; |
| 208 | std::mutex mapping_guard; | 214 | std::mutex mapping_guard; |
| 209 | }; | 215 | }; |
| 210 | 216 | ||
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) { | |||
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | template <typename Traits> | 215 | template <typename Traits> |
| 216 | void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, | 216 | void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, Asid asid, |
| 217 | Asid asid, bool track) { | 217 | bool track) { |
| 218 | Core::Memory::Memory* process_memory = registered_processes[asid.id]; | 218 | Core::Memory::Memory* process_memory = registered_processes[asid.id]; |
| 219 | size_t start_page_d = address >> Memory::YUZU_PAGEBITS; | 219 | size_t start_page_d = address >> Memory::YUZU_PAGEBITS; |
| 220 | size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; | 220 | size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; |
| @@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) { | |||
| 508 | 508 | ||
| 509 | template <typename Traits> | 509 | template <typename Traits> |
| 510 | void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { | 510 | void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { |
| 511 | std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); | 511 | Common::ScopedRangeLock lk(counter_guard, addr, size); |
| 512 | const auto Lock = [&] { | ||
| 513 | if (!lk) { | ||
| 514 | lk.lock(); | ||
| 515 | } | ||
| 516 | }; | ||
| 517 | u64 uncache_begin = 0; | 512 | u64 uncache_begin = 0; |
| 518 | u64 cache_begin = 0; | 513 | u64 cache_begin = 0; |
| 519 | u64 uncache_bytes = 0; | 514 | u64 uncache_bytes = 0; |
| @@ -524,22 +519,36 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||
| 524 | const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); | 519 | const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); |
| 525 | size_t page = addr >> Memory::YUZU_PAGEBITS; | 520 | size_t page = addr >> Memory::YUZU_PAGEBITS; |
| 526 | auto [asid, base_vaddress] = ExtractCPUBacking(page); | 521 | auto [asid, base_vaddress] = ExtractCPUBacking(page); |
| 527 | size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS; | ||
| 528 | auto* memory_device_inter = registered_processes[asid.id]; | 522 | auto* memory_device_inter = registered_processes[asid.id]; |
| 523 | const auto release_pending = [&] { | ||
| 524 | if (uncache_bytes > 0) { | ||
| 525 | MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, | ||
| 526 | uncache_bytes, false); | ||
| 527 | uncache_bytes = 0; | ||
| 528 | } | ||
| 529 | if (cache_bytes > 0) { | ||
| 530 | MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, | ||
| 531 | cache_bytes, true); | ||
| 532 | cache_bytes = 0; | ||
| 533 | } | ||
| 534 | }; | ||
| 529 | for (; page != page_end; ++page) { | 535 | for (; page != page_end; ++page) { |
| 530 | std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); | 536 | CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page); |
| 537 | auto [asid_2, vpage] = ExtractCPUBacking(page); | ||
| 538 | vpage >>= Memory::YUZU_PAGEBITS; | ||
| 531 | 539 | ||
| 532 | if (delta > 0) { | 540 | if (vpage == 0) [[unlikely]] { |
| 533 | ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::max(), | 541 | release_pending(); |
| 534 | "Count may overflow!"); | 542 | continue; |
| 535 | } else if (delta < 0) { | 543 | } |
| 536 | ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); | 544 | |
| 537 | } else { | 545 | if (asid.id != asid_2.id) [[unlikely]] { |
| 538 | ASSERT_MSG(false, "Delta must be non-zero!"); | 546 | release_pending(); |
| 547 | memory_device_inter = registered_processes[asid_2.id]; | ||
| 539 | } | 548 | } |
| 540 | 549 | ||
| 541 | // Adds or subtracts 1, as count is a unsigned 8-bit value | 550 | // Adds or subtracts 1, as count is a unsigned 8-bit value |
| 542 | count.fetch_add(static_cast<u8>(delta), std::memory_order_release); | 551 | count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release); |
| 543 | 552 | ||
| 544 | // Assume delta is either -1 or 1 | 553 | // Assume delta is either -1 or 1 |
| 545 | if (count.load(std::memory_order::relaxed) == 0) { | 554 | if (count.load(std::memory_order::relaxed) == 0) { |
| @@ -548,7 +557,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||
| 548 | } | 557 | } |
| 549 | uncache_bytes += Memory::YUZU_PAGESIZE; | 558 | uncache_bytes += Memory::YUZU_PAGESIZE; |
| 550 | } else if (uncache_bytes > 0) { | 559 | } else if (uncache_bytes > 0) { |
| 551 | Lock(); | ||
| 552 | MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, | 560 | MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, |
| 553 | uncache_bytes, false); | 561 | uncache_bytes, false); |
| 554 | uncache_bytes = 0; | 562 | uncache_bytes = 0; |
| @@ -559,23 +567,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||
| 559 | } | 567 | } |
| 560 | cache_bytes += Memory::YUZU_PAGESIZE; | 568 | cache_bytes += Memory::YUZU_PAGESIZE; |
| 561 | } else if (cache_bytes > 0) { | 569 | } else if (cache_bytes > 0) { |
| 562 | Lock(); | 570 | MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, |
| 563 | MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, | 571 | cache_bytes, true); |
| 564 | true); | ||
| 565 | cache_bytes = 0; | 572 | cache_bytes = 0; |
| 566 | } | 573 | } |
| 567 | vpage++; | ||
| 568 | } | ||
| 569 | if (uncache_bytes > 0) { | ||
| 570 | Lock(); | ||
| 571 | MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, | ||
| 572 | false); | ||
| 573 | } | ||
| 574 | if (cache_bytes > 0) { | ||
| 575 | Lock(); | ||
| 576 | MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, | ||
| 577 | true); | ||
| 578 | } | 574 | } |
| 575 | release_pending(); | ||
| 579 | } | 576 | } |
| 580 | 577 | ||
| 581 | } // namespace Core | 578 | } // 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) { | |||
| 83 | 83 | ||
| 84 | // Check if this memory block is heap. | 84 | // Check if this memory block is heap. |
| 85 | if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { | 85 | if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { |
| 86 | if (svc_mem_info.size > region_size) { | 86 | if (region_start + region_size == svc_mem_info.base_address) { |
| 87 | region_size += svc_mem_info.size; | ||
| 88 | } else if (svc_mem_info.size > region_size) { | ||
| 87 | region_size = svc_mem_info.size; | 89 | region_size = svc_mem_info.size; |
| 88 | region_start = svc_mem_info.base_address; | 90 | region_start = svc_mem_info.base_address; |
| 89 | } | 91 | } |