diff options
| author | 2023-12-25 07:32:16 +0100 | |
|---|---|---|
| committer | 2024-01-18 21:12:30 -0500 | |
| commit | 0a2536a0df1f4aea406f2132d3edda0430acc9d1 (patch) | |
| tree | c0ad53890581c9c7e180c5ccb3b66e3c63e3ba64 /src/core | |
| parent | SMMU: Implement backing CPU page protect/unprotect (diff) | |
| download | yuzu-0a2536a0df1f4aea406f2132d3edda0430acc9d1.tar.gz yuzu-0a2536a0df1f4aea406f2132d3edda0430acc9d1.tar.xz yuzu-0a2536a0df1f4aea406f2132d3edda0430acc9d1.zip | |
SMMU: Initial adaptation to video_core.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/core.cpp | 2 | ||||
| -rw-r--r-- | src/core/core.h | 2 | ||||
| -rw-r--r-- | src/core/device_memory_manager.h | 43 | ||||
| -rw-r--r-- | src/core/device_memory_manager.inc | 72 | ||||
| -rw-r--r-- | src/core/gpu_dirty_memory_manager.h | 10 | ||||
| -rw-r--r-- | src/core/guest_memory.h | 218 | ||||
| -rw-r--r-- | src/core/hle/service/hle_ipc.cpp | 61 | ||||
| -rw-r--r-- | src/core/hle/service/hle_ipc.h | 9 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/core/nvmap.cpp | 64 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/core/nvmap.h | 19 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | 57 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h | 20 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvmap.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv_interface.cpp | 6 | ||||
| -rw-r--r-- | src/core/memory.cpp | 25 | ||||
| -rw-r--r-- | src/core/memory.h | 205 |
19 files changed, 441 insertions, 388 deletions
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 | |||
| 37 | debugger/gdbstub_arch.h | 37 | debugger/gdbstub_arch.h |
| 38 | debugger/gdbstub.cpp | 38 | debugger/gdbstub.cpp |
| 39 | debugger/gdbstub.h | 39 | debugger/gdbstub.h |
| 40 | device_memory_manager.h | ||
| 41 | device_memory_manager.inc | ||
| 40 | device_memory.cpp | 42 | device_memory.cpp |
| 41 | device_memory.h | 43 | device_memory.h |
| 42 | file_sys/fssystem/fs_i_storage.h | 44 | 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 { | |||
| 651 | return impl->kernel.GetCurrentHostThreadID(); | 651 | return impl->kernel.GetCurrentHostThreadID(); |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { | 654 | void System::GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback) { |
| 655 | return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); | 655 | return this->ApplicationProcess()->GatherGPUDirtyMemory(callback); |
| 656 | } | 656 | } |
| 657 | 657 | ||
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: | |||
| 224 | /// Prepare the core emulation for a reschedule | 224 | /// Prepare the core emulation for a reschedule |
| 225 | void PrepareReschedule(u32 core_index); | 225 | void PrepareReschedule(u32 core_index); |
| 226 | 226 | ||
| 227 | void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); | 227 | void GatherGPUDirtyMemory(std::function<void(PAddr, size_t)>& callback); |
| 228 | 228 | ||
| 229 | [[nodiscard]] size_t GetCurrentHostThreadID() const; | 229 | [[nodiscard]] size_t GetCurrentHostThreadID() const; |
| 230 | 230 | ||
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 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <deque> | ||
| 7 | #include <memory> | ||
| 8 | #include <array> | 6 | #include <array> |
| 9 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <deque> | ||
| 9 | #include <memory> | ||
| 10 | #include <mutex> | ||
| 10 | 11 | ||
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 12 | #include "common/virtual_buffer.h" | 13 | #include "common/virtual_buffer.h" |
| @@ -48,26 +49,54 @@ public: | |||
| 48 | template <typename T> | 49 | template <typename T> |
| 49 | const T* GetPointer(DAddr address) const; | 50 | const T* GetPointer(DAddr address) const; |
| 50 | 51 | ||
| 52 | DAddr GetAddressFromPAddr(PAddr address) const { | ||
| 53 | DAddr subbits = static_cast<DAddr>(address & page_mask); | ||
| 54 | return (static_cast<DAddr>(compressed_device_addr[(address >> page_bits)]) << page_bits) + subbits; | ||
| 55 | } | ||
| 56 | |||
| 57 | PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const { | ||
| 58 | PAddr subbits = static_cast<PAddr>(address & page_mask); | ||
| 59 | auto paddr = compressed_physical_ptr[(address >> page_bits)]; | ||
| 60 | if (paddr == 0) { | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | return (static_cast<PAddr>(paddr - 1) << page_bits) + subbits; | ||
| 64 | } | ||
| 65 | |||
| 51 | template <typename T> | 66 | template <typename T> |
| 52 | void Write(DAddr address, T value); | 67 | void Write(DAddr address, T value); |
| 53 | 68 | ||
| 54 | template <typename T> | 69 | template <typename T> |
| 55 | T Read(DAddr address) const; | 70 | T Read(DAddr address) const; |
| 56 | 71 | ||
| 72 | const u8* GetSpan(const DAddr src_addr, const std::size_t size) const { | ||
| 73 | return nullptr; | ||
| 74 | } | ||
| 75 | |||
| 76 | u8* GetSpan(const DAddr src_addr, const std::size_t size) { | ||
| 77 | return nullptr; | ||
| 78 | } | ||
| 79 | |||
| 57 | void ReadBlock(DAddr address, void* dest_pointer, size_t size); | 80 | void ReadBlock(DAddr address, void* dest_pointer, size_t size); |
| 58 | void WriteBlock(DAddr address, void* src_pointer, size_t size); | 81 | void ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size); |
| 82 | void WriteBlock(DAddr address, const void* src_pointer, size_t size); | ||
| 83 | void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size); | ||
| 59 | 84 | ||
| 60 | size_t RegisterProcess(Memory::Memory* memory); | 85 | size_t RegisterProcess(Memory::Memory* memory); |
| 61 | void UnregisterProcess(size_t id); | 86 | void UnregisterProcess(size_t id); |
| 62 | 87 | ||
| 63 | void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta); | 88 | void UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta); |
| 64 | 89 | ||
| 90 | static constexpr size_t AS_BITS = Traits::device_virtual_bits; | ||
| 91 | |||
| 65 | private: | 92 | private: |
| 66 | static constexpr bool supports_pinning = Traits::supports_pinning; | 93 | static constexpr bool supports_pinning = Traits::supports_pinning; |
| 67 | static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; | 94 | static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; |
| 68 | static constexpr size_t device_as_size = 1ULL << device_virtual_bits; | 95 | static constexpr size_t device_as_size = 1ULL << device_virtual_bits; |
| 69 | static constexpr size_t physical_max_bits = 33; | 96 | static constexpr size_t physical_max_bits = 33; |
| 70 | static constexpr size_t page_bits = 12; | 97 | static constexpr size_t page_bits = 12; |
| 98 | static constexpr size_t page_size = 1ULL << page_bits; | ||
| 99 | static constexpr size_t page_mask = page_size - 1ULL; | ||
| 71 | static constexpr u32 physical_address_base = 1U << page_bits; | 100 | static constexpr u32 physical_address_base = 1U << page_bits; |
| 72 | 101 | ||
| 73 | template <typename T> | 102 | template <typename T> |
| @@ -136,11 +165,15 @@ private: | |||
| 136 | private: | 165 | private: |
| 137 | std::array<std::atomic_uint16_t, subentries> values{}; | 166 | std::array<std::atomic_uint16_t, subentries> values{}; |
| 138 | }; | 167 | }; |
| 139 | static_assert(sizeof(CounterEntry) == subentries * sizeof(u16), "CounterEntry should be 8 bytes!"); | 168 | static_assert(sizeof(CounterEntry) == subentries * sizeof(u16), |
| 169 | "CounterEntry should be 8 bytes!"); | ||
| 140 | 170 | ||
| 141 | static constexpr size_t num_counter_entries = (1ULL << (device_virtual_bits - page_bits)) / subentries; | 171 | static constexpr size_t num_counter_entries = |
| 172 | (1ULL << (device_virtual_bits - page_bits)) / subentries; | ||
| 142 | using CachedPages = std::array<CounterEntry, num_counter_entries>; | 173 | using CachedPages = std::array<CounterEntry, num_counter_entries>; |
| 143 | std::unique_ptr<CachedPages> cached_pages; | 174 | std::unique_ptr<CachedPages> cached_pages; |
| 175 | std::mutex counter_guard; | ||
| 176 | std::mutex mapping_guard; | ||
| 144 | }; | 177 | }; |
| 145 | 178 | ||
| 146 | } // namespace Core \ No newline at end of file | 179 | } // 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 <typename Traits> | |||
| 105 | DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_) | 105 | DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_) |
| 106 | : physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())}, | 106 | : physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())}, |
| 107 | interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), | 107 | interface{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), |
| 108 | compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)) { | 108 | compressed_device_addr(1ULL << (physical_max_bits - Memory::YUZU_PAGEBITS)), |
| 109 | cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) { | ||
| 109 | impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>(); | 110 | impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>(); |
| 110 | cached_pages = std::make_unique<CachedPages>(); | 111 | cached_pages = std::make_unique<CachedPages>(); |
| 111 | } | 112 | } |
| @@ -144,10 +145,10 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size | |||
| 144 | Core::Memory::Memory* process_memory = registered_processes[process_id]; | 145 | Core::Memory::Memory* process_memory = registered_processes[process_id]; |
| 145 | size_t start_page_d = address >> Memory::YUZU_PAGEBITS; | 146 | size_t start_page_d = address >> Memory::YUZU_PAGEBITS; |
| 146 | size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; | 147 | size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; |
| 147 | std::atomic_thread_fence(std::memory_order_acquire); | 148 | std::scoped_lock lk(mapping_guard); |
| 148 | for (size_t i = 0; i < num_pages; i++) { | 149 | for (size_t i = 0; i < num_pages; i++) { |
| 149 | const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE; | 150 | const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE; |
| 150 | auto* ptr = process_memory->GetPointer(Common::ProcessAddress(new_vaddress)); | 151 | auto* ptr = process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress)); |
| 151 | if (ptr == nullptr) [[unlikely]] { | 152 | if (ptr == nullptr) [[unlikely]] { |
| 152 | compressed_physical_ptr[start_page_d + i] = 0; | 153 | compressed_physical_ptr[start_page_d + i] = 0; |
| 153 | continue; | 154 | continue; |
| @@ -157,14 +158,14 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size | |||
| 157 | compressed_device_addr[phys_addr - 1U] = static_cast<u32>(start_page_d + i); | 158 | compressed_device_addr[phys_addr - 1U] = static_cast<u32>(start_page_d + i); |
| 158 | InsertCPUBacking(start_page_d + i, new_vaddress, process_id); | 159 | InsertCPUBacking(start_page_d + i, new_vaddress, process_id); |
| 159 | } | 160 | } |
| 160 | std::atomic_thread_fence(std::memory_order_release); | ||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | template <typename Traits> | 163 | template <typename Traits> |
| 164 | void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) { | 164 | void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) { |
| 165 | size_t start_page_d = address >> Memory::YUZU_PAGEBITS; | 165 | size_t start_page_d = address >> Memory::YUZU_PAGEBITS; |
| 166 | size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; | 166 | size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; |
| 167 | std::atomic_thread_fence(std::memory_order_acquire); | 167 | interface->InvalidateRegion(address, size); |
| 168 | std::scoped_lock lk(mapping_guard); | ||
| 168 | for (size_t i = 0; i < num_pages; i++) { | 169 | for (size_t i = 0; i < num_pages; i++) { |
| 169 | auto phys_addr = compressed_physical_ptr[start_page_d + i]; | 170 | auto phys_addr = compressed_physical_ptr[start_page_d + i]; |
| 170 | compressed_physical_ptr[start_page_d + i] = 0; | 171 | compressed_physical_ptr[start_page_d + i] = 0; |
| @@ -173,7 +174,6 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) { | |||
| 173 | compressed_device_addr[phys_addr - 1] = 0; | 174 | compressed_device_addr[phys_addr - 1] = 0; |
| 174 | } | 175 | } |
| 175 | } | 176 | } |
| 176 | std::atomic_thread_fence(std::memory_order_release); | ||
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | template <typename Traits> | 179 | template <typename Traits> |
| @@ -256,6 +256,45 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o | |||
| 256 | 256 | ||
| 257 | template <typename Traits> | 257 | template <typename Traits> |
| 258 | void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) { | 258 | void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) { |
| 259 | interface->FlushRegion(address, size); | ||
| 260 | WalkBlock( | ||
| 261 | address, size, | ||
| 262 | [&](size_t copy_amount, DAddr current_vaddr) { | ||
| 263 | LOG_ERROR( | ||
| 264 | HW_Memory, | ||
| 265 | "Unmapped Device ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | ||
| 266 | current_vaddr, address, size); | ||
| 267 | std::memset(dest_pointer, 0, copy_amount); | ||
| 268 | }, | ||
| 269 | [&](size_t copy_amount, const u8* const src_ptr) { | ||
| 270 | std::memcpy(dest_pointer, src_ptr, copy_amount); | ||
| 271 | }, | ||
| 272 | [&](const std::size_t copy_amount) { | ||
| 273 | dest_pointer = static_cast<u8*>(dest_pointer) + copy_amount; | ||
| 274 | }); | ||
| 275 | } | ||
| 276 | |||
| 277 | template <typename Traits> | ||
| 278 | void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, const void* src_pointer, size_t size) { | ||
| 279 | WalkBlock( | ||
| 280 | address, size, | ||
| 281 | [&](size_t copy_amount, DAddr current_vaddr) { | ||
| 282 | LOG_ERROR( | ||
| 283 | HW_Memory, | ||
| 284 | "Unmapped Device WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", | ||
| 285 | current_vaddr, address, size); | ||
| 286 | }, | ||
| 287 | [&](size_t copy_amount, u8* const dst_ptr) { | ||
| 288 | std::memcpy(dst_ptr, src_pointer, copy_amount); | ||
| 289 | }, | ||
| 290 | [&](const std::size_t copy_amount) { | ||
| 291 | src_pointer = static_cast<const u8*>(src_pointer) + copy_amount; | ||
| 292 | }); | ||
| 293 | interface->InvalidateRegion(address, size); | ||
| 294 | } | ||
| 295 | |||
| 296 | template <typename Traits> | ||
| 297 | void DeviceMemoryManager<Traits>::ReadBlockUnsafe(DAddr address, void* dest_pointer, size_t size) { | ||
| 259 | WalkBlock( | 298 | WalkBlock( |
| 260 | address, size, | 299 | address, size, |
| 261 | [&](size_t copy_amount, DAddr current_vaddr) { | 300 | [&](size_t copy_amount, DAddr current_vaddr) { |
| @@ -274,7 +313,8 @@ void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, s | |||
| 274 | } | 313 | } |
| 275 | 314 | ||
| 276 | template <typename Traits> | 315 | template <typename Traits> |
| 277 | void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, void* src_pointer, size_t size) { | 316 | void DeviceMemoryManager<Traits>::WriteBlockUnsafe(DAddr address, const void* src_pointer, |
| 317 | size_t size) { | ||
| 278 | WalkBlock( | 318 | WalkBlock( |
| 279 | address, size, | 319 | address, size, |
| 280 | [&](size_t copy_amount, DAddr current_vaddr) { | 320 | [&](size_t copy_amount, DAddr current_vaddr) { |
| @@ -287,7 +327,7 @@ void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, void* src_pointer, s | |||
| 287 | std::memcpy(dst_ptr, src_pointer, copy_amount); | 327 | std::memcpy(dst_ptr, src_pointer, copy_amount); |
| 288 | }, | 328 | }, |
| 289 | [&](const std::size_t copy_amount) { | 329 | [&](const std::size_t copy_amount) { |
| 290 | src_pointer = static_cast<u8*>(src_pointer) + copy_amount; | 330 | src_pointer = static_cast<const u8*>(src_pointer) + copy_amount; |
| 291 | }); | 331 | }); |
| 292 | } | 332 | } |
| 293 | 333 | ||
| @@ -313,6 +353,18 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(size_t id) { | |||
| 313 | 353 | ||
| 314 | template <typename Traits> | 354 | template <typename Traits> |
| 315 | void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { | 355 | void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { |
| 356 | bool locked = false; | ||
| 357 | auto lock = [&] { | ||
| 358 | if (!locked) { | ||
| 359 | counter_guard.lock(); | ||
| 360 | locked = true; | ||
| 361 | } | ||
| 362 | }; | ||
| 363 | SCOPE_EXIT({ | ||
| 364 | if (locked) { | ||
| 365 | counter_guard.unlock(); | ||
| 366 | } | ||
| 367 | }); | ||
| 316 | u64 uncache_begin = 0; | 368 | u64 uncache_begin = 0; |
| 317 | u64 cache_begin = 0; | 369 | u64 cache_begin = 0; |
| 318 | u64 uncache_bytes = 0; | 370 | u64 uncache_bytes = 0; |
| @@ -347,6 +399,7 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||
| 347 | } | 399 | } |
| 348 | uncache_bytes += Memory::YUZU_PAGESIZE; | 400 | uncache_bytes += Memory::YUZU_PAGESIZE; |
| 349 | } else if (uncache_bytes > 0) { | 401 | } else if (uncache_bytes > 0) { |
| 402 | lock(); | ||
| 350 | MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, | 403 | MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, |
| 351 | uncache_bytes, false); | 404 | uncache_bytes, false); |
| 352 | uncache_bytes = 0; | 405 | uncache_bytes = 0; |
| @@ -357,6 +410,7 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||
| 357 | } | 410 | } |
| 358 | cache_bytes += Memory::YUZU_PAGESIZE; | 411 | cache_bytes += Memory::YUZU_PAGESIZE; |
| 359 | } else if (cache_bytes > 0) { | 412 | } else if (cache_bytes > 0) { |
| 413 | lock(); | ||
| 360 | MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, | 414 | MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, |
| 361 | true); | 415 | true); |
| 362 | cache_bytes = 0; | 416 | cache_bytes = 0; |
| @@ -364,10 +418,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size | |||
| 364 | vpage++; | 418 | vpage++; |
| 365 | } | 419 | } |
| 366 | if (uncache_bytes > 0) { | 420 | if (uncache_bytes > 0) { |
| 421 | lock(); | ||
| 367 | MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, | 422 | MarkRegionCaching(memory_interface, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes, |
| 368 | false); | 423 | false); |
| 369 | } | 424 | } |
| 370 | if (cache_bytes > 0) { | 425 | if (cache_bytes > 0) { |
| 426 | lock(); | ||
| 371 | MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, | 427 | MarkRegionCaching(memory_interface, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, |
| 372 | true); | 428 | true); |
| 373 | } | 429 | } |
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: | |||
| 23 | 23 | ||
| 24 | ~GPUDirtyMemoryManager() = default; | 24 | ~GPUDirtyMemoryManager() = default; |
| 25 | 25 | ||
| 26 | void Collect(VAddr address, size_t size) { | 26 | void Collect(PAddr address, size_t size) { |
| 27 | TransformAddress t = BuildTransform(address, size); | 27 | TransformAddress t = BuildTransform(address, size); |
| 28 | TransformAddress tmp, original; | 28 | TransformAddress tmp, original; |
| 29 | do { | 29 | do { |
| @@ -47,7 +47,7 @@ public: | |||
| 47 | std::memory_order_relaxed)); | 47 | std::memory_order_relaxed)); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | void Gather(std::function<void(VAddr, size_t)>& callback) { | 50 | void Gather(std::function<void(PAddr, size_t)>& callback) { |
| 51 | { | 51 | { |
| 52 | std::scoped_lock lk(guard); | 52 | std::scoped_lock lk(guard); |
| 53 | TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed); | 53 | TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed); |
| @@ -65,7 +65,7 @@ public: | |||
| 65 | mask = mask >> empty_bits; | 65 | mask = mask >> empty_bits; |
| 66 | 66 | ||
| 67 | const size_t continuous_bits = std::countr_one(mask); | 67 | const size_t continuous_bits = std::countr_one(mask); |
| 68 | callback((static_cast<VAddr>(transform.address) << page_bits) + offset, | 68 | callback((static_cast<PAddr>(transform.address) << page_bits) + offset, |
| 69 | continuous_bits << align_bits); | 69 | continuous_bits << align_bits); |
| 70 | mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0; | 70 | mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0; |
| 71 | offset += continuous_bits << align_bits; | 71 | offset += continuous_bits << align_bits; |
| @@ -89,7 +89,7 @@ private: | |||
| 89 | constexpr static size_t align_mask = align_size - 1; | 89 | constexpr static size_t align_mask = align_size - 1; |
| 90 | constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U}; | 90 | constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U}; |
| 91 | 91 | ||
| 92 | bool IsValid(VAddr address) { | 92 | bool IsValid(PAddr address) { |
| 93 | return address < (1ULL << 39); | 93 | return address < (1ULL << 39); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| @@ -103,7 +103,7 @@ private: | |||
| 103 | return mask; | 103 | return mask; |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | TransformAddress BuildTransform(VAddr address, size_t size) { | 106 | TransformAddress BuildTransform(PAddr address, size_t size) { |
| 107 | const size_t minor_address = address & page_mask; | 107 | const size_t minor_address = address & page_mask; |
| 108 | const size_t minor_bit = minor_address >> align_bits; | 108 | const size_t minor_bit = minor_address >> align_bits; |
| 109 | const size_t top_bit = (minor_address + size + align_mask) >> align_bits; | 109 | 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <iterator> | ||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | #include <span> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include "common/scratch_buffer.h" | ||
| 13 | #include "core/memory.h" | ||
| 14 | |||
| 15 | namespace Core::Memory { | ||
| 16 | |||
| 17 | enum GuestMemoryFlags : u32 { | ||
| 18 | Read = 1 << 0, | ||
| 19 | Write = 1 << 1, | ||
| 20 | Safe = 1 << 2, | ||
| 21 | Cached = 1 << 3, | ||
| 22 | |||
| 23 | SafeRead = Read | Safe, | ||
| 24 | SafeWrite = Write | Safe, | ||
| 25 | SafeReadWrite = SafeRead | SafeWrite, | ||
| 26 | SafeReadCachedWrite = SafeReadWrite | Cached, | ||
| 27 | |||
| 28 | UnsafeRead = Read, | ||
| 29 | UnsafeWrite = Write, | ||
| 30 | UnsafeReadWrite = UnsafeRead | UnsafeWrite, | ||
| 31 | UnsafeReadCachedWrite = UnsafeReadWrite | Cached, | ||
| 32 | }; | ||
| 33 | |||
| 34 | namespace { | ||
| 35 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 36 | class GuestMemory { | ||
| 37 | using iterator = T*; | ||
| 38 | using const_iterator = const T*; | ||
| 39 | using value_type = T; | ||
| 40 | using element_type = T; | ||
| 41 | using iterator_category = std::contiguous_iterator_tag; | ||
| 42 | |||
| 43 | public: | ||
| 44 | GuestMemory() = delete; | ||
| 45 | explicit GuestMemory(M& memory, u64 addr, std::size_t size, | ||
| 46 | Common::ScratchBuffer<T>* backup = nullptr) | ||
| 47 | : m_memory{memory}, m_addr{addr}, m_size{size} { | ||
| 48 | static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write); | ||
| 49 | if constexpr (FLAGS & GuestMemoryFlags::Read) { | ||
| 50 | Read(addr, size, backup); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | ~GuestMemory() = default; | ||
| 55 | |||
| 56 | T* data() noexcept { | ||
| 57 | return m_data_span.data(); | ||
| 58 | } | ||
| 59 | |||
| 60 | const T* data() const noexcept { | ||
| 61 | return m_data_span.data(); | ||
| 62 | } | ||
| 63 | |||
| 64 | size_t size() const noexcept { | ||
| 65 | return m_size; | ||
| 66 | } | ||
| 67 | |||
| 68 | size_t size_bytes() const noexcept { | ||
| 69 | return this->size() * sizeof(T); | ||
| 70 | } | ||
| 71 | |||
| 72 | [[nodiscard]] T* begin() noexcept { | ||
| 73 | return this->data(); | ||
| 74 | } | ||
| 75 | |||
| 76 | [[nodiscard]] const T* begin() const noexcept { | ||
| 77 | return this->data(); | ||
| 78 | } | ||
| 79 | |||
| 80 | [[nodiscard]] T* end() noexcept { | ||
| 81 | return this->data() + this->size(); | ||
| 82 | } | ||
| 83 | |||
| 84 | [[nodiscard]] const T* end() const noexcept { | ||
| 85 | return this->data() + this->size(); | ||
| 86 | } | ||
| 87 | |||
| 88 | T& operator[](size_t index) noexcept { | ||
| 89 | return m_data_span[index]; | ||
| 90 | } | ||
| 91 | |||
| 92 | const T& operator[](size_t index) const noexcept { | ||
| 93 | return m_data_span[index]; | ||
| 94 | } | ||
| 95 | |||
| 96 | void SetAddressAndSize(u64 addr, std::size_t size) noexcept { | ||
| 97 | m_addr = addr; | ||
| 98 | m_size = size; | ||
| 99 | m_addr_changed = true; | ||
| 100 | } | ||
| 101 | |||
| 102 | std::span<T> Read(u64 addr, std::size_t size, | ||
| 103 | Common::ScratchBuffer<T>* backup = nullptr) noexcept { | ||
| 104 | m_addr = addr; | ||
| 105 | m_size = size; | ||
| 106 | if (m_size == 0) { | ||
| 107 | m_is_data_copy = true; | ||
| 108 | return {}; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (this->TrySetSpan()) { | ||
| 112 | if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 113 | m_memory.FlushRegion(m_addr, this->size_bytes()); | ||
| 114 | } | ||
| 115 | } else { | ||
| 116 | if (backup) { | ||
| 117 | backup->resize_destructive(this->size()); | ||
| 118 | m_data_span = *backup; | ||
| 119 | } else { | ||
| 120 | m_data_copy.resize(this->size()); | ||
| 121 | m_data_span = std::span(m_data_copy); | ||
| 122 | } | ||
| 123 | m_is_data_copy = true; | ||
| 124 | m_span_valid = true; | ||
| 125 | if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 126 | m_memory.ReadBlock(m_addr, this->data(), this->size_bytes()); | ||
| 127 | } else { | ||
| 128 | m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes()); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | return m_data_span; | ||
| 132 | } | ||
| 133 | |||
| 134 | void Write(std::span<T> write_data) noexcept { | ||
| 135 | if constexpr (FLAGS & GuestMemoryFlags::Cached) { | ||
| 136 | m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes()); | ||
| 137 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 138 | m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes()); | ||
| 139 | } else { | ||
| 140 | m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes()); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | bool TrySetSpan() noexcept { | ||
| 145 | if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) { | ||
| 146 | m_data_span = {reinterpret_cast<T*>(ptr), this->size()}; | ||
| 147 | m_span_valid = true; | ||
| 148 | return true; | ||
| 149 | } | ||
| 150 | return false; | ||
| 151 | } | ||
| 152 | |||
| 153 | protected: | ||
| 154 | bool IsDataCopy() const noexcept { | ||
| 155 | return m_is_data_copy; | ||
| 156 | } | ||
| 157 | |||
| 158 | bool AddressChanged() const noexcept { | ||
| 159 | return m_addr_changed; | ||
| 160 | } | ||
| 161 | |||
| 162 | M& m_memory; | ||
| 163 | u64 m_addr{}; | ||
| 164 | size_t m_size{}; | ||
| 165 | std::span<T> m_data_span{}; | ||
| 166 | std::vector<T> m_data_copy{}; | ||
| 167 | bool m_span_valid{false}; | ||
| 168 | bool m_is_data_copy{false}; | ||
| 169 | bool m_addr_changed{false}; | ||
| 170 | }; | ||
| 171 | |||
| 172 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 173 | class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> { | ||
| 174 | public: | ||
| 175 | GuestMemoryScoped() = delete; | ||
| 176 | explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size, | ||
| 177 | Common::ScratchBuffer<T>* backup = nullptr) | ||
| 178 | : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) { | ||
| 179 | if constexpr (!(FLAGS & GuestMemoryFlags::Read)) { | ||
| 180 | if (!this->TrySetSpan()) { | ||
| 181 | if (backup) { | ||
| 182 | this->m_data_span = *backup; | ||
| 183 | this->m_span_valid = true; | ||
| 184 | this->m_is_data_copy = true; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | ~GuestMemoryScoped() { | ||
| 191 | if constexpr (FLAGS & GuestMemoryFlags::Write) { | ||
| 192 | if (this->size() == 0) [[unlikely]] { | ||
| 193 | return; | ||
| 194 | } | ||
| 195 | |||
| 196 | if (this->AddressChanged() || this->IsDataCopy()) { | ||
| 197 | ASSERT(this->m_span_valid); | ||
| 198 | if constexpr (FLAGS & GuestMemoryFlags::Cached) { | ||
| 199 | this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes()); | ||
| 200 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 201 | this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes()); | ||
| 202 | } else { | ||
| 203 | this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes()); | ||
| 204 | } | ||
| 205 | } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || (FLAGS & GuestMemoryFlags::Cached)) { | ||
| 206 | this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes()); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } | ||
| 210 | }; | ||
| 211 | } // namespace | ||
| 212 | |||
| 213 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 214 | using CpuGuestMemory = GuestMemory<Core::Memory::Memory, T, FLAGS>; | ||
| 215 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 216 | using CpuGuestMemoryScoped = GuestMemoryScoped<Core::Memory::Memory, T, FLAGS>; | ||
| 217 | |||
| 218 | } // 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 @@ | |||
| 22 | #include "core/hle/service/hle_ipc.h" | 22 | #include "core/hle/service/hle_ipc.h" |
| 23 | #include "core/hle/service/ipc_helpers.h" | 23 | #include "core/hle/service/ipc_helpers.h" |
| 24 | #include "core/memory.h" | 24 | #include "core/memory.h" |
| 25 | 25 | #include "core/guest_memory.h" | |
| 26 | namespace { | ||
| 27 | static thread_local std::array read_buffer_data_a{ | ||
| 28 | Common::ScratchBuffer<u8>(), | ||
| 29 | Common::ScratchBuffer<u8>(), | ||
| 30 | Common::ScratchBuffer<u8>(), | ||
| 31 | }; | ||
| 32 | static thread_local std::array read_buffer_data_x{ | ||
| 33 | Common::ScratchBuffer<u8>(), | ||
| 34 | Common::ScratchBuffer<u8>(), | ||
| 35 | Common::ScratchBuffer<u8>(), | ||
| 36 | }; | ||
| 37 | } // Anonymous namespace | ||
| 38 | 26 | ||
| 39 | namespace Service { | 27 | namespace Service { |
| 40 | 28 | ||
| @@ -343,48 +331,27 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons | |||
| 343 | } | 331 | } |
| 344 | 332 | ||
| 345 | std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const { | 333 | std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const { |
| 346 | static thread_local std::array read_buffer_a{ | 334 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0); |
| 347 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 348 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 349 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 350 | }; | ||
| 351 | 335 | ||
| 352 | ASSERT_OR_EXECUTE_MSG( | 336 | ASSERT_OR_EXECUTE_MSG( |
| 353 | BufferDescriptorA().size() > buffer_index, { return {}; }, | 337 | BufferDescriptorA().size() > buffer_index, { return {}; }, |
| 354 | "BufferDescriptorA invalid buffer_index {}", buffer_index); | 338 | "BufferDescriptorA invalid buffer_index {}", buffer_index); |
| 355 | auto& read_buffer = read_buffer_a[buffer_index]; | 339 | return gm.Read(BufferDescriptorA()[buffer_index].Address(), |
| 356 | return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), | 340 | BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]); |
| 357 | BufferDescriptorA()[buffer_index].Size(), | ||
| 358 | &read_buffer_data_a[buffer_index]); | ||
| 359 | } | 341 | } |
| 360 | 342 | ||
| 361 | std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const { | 343 | std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const { |
| 362 | static thread_local std::array read_buffer_x{ | 344 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0); |
| 363 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 364 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 365 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 366 | }; | ||
| 367 | 345 | ||
| 368 | ASSERT_OR_EXECUTE_MSG( | 346 | ASSERT_OR_EXECUTE_MSG( |
| 369 | BufferDescriptorX().size() > buffer_index, { return {}; }, | 347 | BufferDescriptorX().size() > buffer_index, { return {}; }, |
| 370 | "BufferDescriptorX invalid buffer_index {}", buffer_index); | 348 | "BufferDescriptorX invalid buffer_index {}", buffer_index); |
| 371 | auto& read_buffer = read_buffer_x[buffer_index]; | 349 | return gm.Read(BufferDescriptorX()[buffer_index].Address(), |
| 372 | return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), | 350 | BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]); |
| 373 | BufferDescriptorX()[buffer_index].Size(), | ||
| 374 | &read_buffer_data_x[buffer_index]); | ||
| 375 | } | 351 | } |
| 376 | 352 | ||
| 377 | std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { | 353 | std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { |
| 378 | static thread_local std::array read_buffer_a{ | 354 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0); |
| 379 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 380 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 381 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 382 | }; | ||
| 383 | static thread_local std::array read_buffer_x{ | ||
| 384 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 385 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 386 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 387 | }; | ||
| 388 | 355 | ||
| 389 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | 356 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && |
| 390 | BufferDescriptorA()[buffer_index].Size()}; | 357 | BufferDescriptorA()[buffer_index].Size()}; |
| @@ -401,18 +368,14 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons | |||
| 401 | ASSERT_OR_EXECUTE_MSG( | 368 | ASSERT_OR_EXECUTE_MSG( |
| 402 | BufferDescriptorA().size() > buffer_index, { return {}; }, | 369 | BufferDescriptorA().size() > buffer_index, { return {}; }, |
| 403 | "BufferDescriptorA invalid buffer_index {}", buffer_index); | 370 | "BufferDescriptorA invalid buffer_index {}", buffer_index); |
| 404 | auto& read_buffer = read_buffer_a[buffer_index]; | 371 | return gm.Read(BufferDescriptorA()[buffer_index].Address(), |
| 405 | return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), | 372 | BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]); |
| 406 | BufferDescriptorA()[buffer_index].Size(), | ||
| 407 | &read_buffer_data_a[buffer_index]); | ||
| 408 | } else { | 373 | } else { |
| 409 | ASSERT_OR_EXECUTE_MSG( | 374 | ASSERT_OR_EXECUTE_MSG( |
| 410 | BufferDescriptorX().size() > buffer_index, { return {}; }, | 375 | BufferDescriptorX().size() > buffer_index, { return {}; }, |
| 411 | "BufferDescriptorX invalid buffer_index {}", buffer_index); | 376 | "BufferDescriptorX invalid buffer_index {}", buffer_index); |
| 412 | auto& read_buffer = read_buffer_x[buffer_index]; | 377 | return gm.Read(BufferDescriptorX()[buffer_index].Address(), |
| 413 | return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), | 378 | BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]); |
| 414 | BufferDescriptorX()[buffer_index].Size(), | ||
| 415 | &read_buffer_data_x[buffer_index]); | ||
| 416 | } | 379 | } |
| 417 | } | 380 | } |
| 418 | 381 | ||
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 @@ | |||
| 19 | #include "core/hle/ipc.h" | 19 | #include "core/hle/ipc.h" |
| 20 | #include "core/hle/kernel/k_handle_table.h" | 20 | #include "core/hle/kernel/k_handle_table.h" |
| 21 | #include "core/hle/kernel/svc_common.h" | 21 | #include "core/hle/kernel/svc_common.h" |
| 22 | #include "core/hle/kernel/k_auto_object.h" | ||
| 23 | #include "core/hle/kernel/k_handle_table.h" | ||
| 24 | 22 | ||
| 25 | union Result; | 23 | union Result; |
| 26 | 24 | ||
| @@ -377,10 +375,6 @@ public: | |||
| 377 | return nullptr; | 375 | return nullptr; |
| 378 | } | 376 | } |
| 379 | 377 | ||
| 380 | Kernel::KScopedAutoObject<Kernel::KAutoObject> GetObjectFromHandle(u32 handle) { | ||
| 381 | return GetClientHandleTable().GetObjectForIpc(handle, thread); | ||
| 382 | } | ||
| 383 | |||
| 384 | [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { | 378 | [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { |
| 385 | return manager.lock(); | 379 | return manager.lock(); |
| 386 | } | 380 | } |
| @@ -432,6 +426,9 @@ private: | |||
| 432 | 426 | ||
| 433 | Kernel::KernelCore& kernel; | 427 | Kernel::KernelCore& kernel; |
| 434 | Core::Memory::Memory& memory; | 428 | Core::Memory::Memory& memory; |
| 429 | |||
| 430 | mutable std::array<Common::ScratchBuffer<u8>, 3> read_buffer_data_a{}; | ||
| 431 | mutable std::array<Common::ScratchBuffer<u8>, 3> read_buffer_data_x{}; | ||
| 435 | }; | 432 | }; |
| 436 | 433 | ||
| 437 | } // namespace Service | 434 | } // 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 @@ | |||
| 2 | // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors | 2 | // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors |
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later | 3 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 4 | 4 | ||
| 5 | #include <functional> | ||
| 6 | |||
| 5 | #include "common/alignment.h" | 7 | #include "common/alignment.h" |
| 6 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| @@ -18,6 +20,7 @@ NvMap::Handle::Handle(u64 size_, Id id_) | |||
| 18 | } | 20 | } |
| 19 | 21 | ||
| 20 | NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { | 22 | NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { |
| 23 | std::scoped_lock lock(mutex); | ||
| 21 | // Handles cannot be allocated twice | 24 | // Handles cannot be allocated twice |
| 22 | if (allocated) { | 25 | if (allocated) { |
| 23 | return NvResult::AccessDenied; | 26 | return NvResult::AccessDenied; |
| @@ -78,11 +81,9 @@ void NvMap::UnmapHandle(Handle& handle_description) { | |||
| 78 | 81 | ||
| 79 | // Free and unmap the handle from the SMMU | 82 | // Free and unmap the handle from the SMMU |
| 80 | auto& smmu = host1x.MemoryManager(); | 83 | auto& smmu = host1x.MemoryManager(); |
| 81 | smmu.Unmap(static_cast<DAddr>(handle_description.pin_virt_address), | 84 | smmu.Unmap(handle_description.d_address, handle_description.aligned_size); |
| 82 | handle_description.aligned_size); | 85 | smmu.Free(handle_description.d_address, static_cast<size_t>(handle_description.aligned_size)); |
| 83 | smmu.Free(handle_description.pin_virt_address, | 86 | handle_description.d_address = 0; |
| 84 | static_cast<size_t>(handle_description.aligned_size)); | ||
| 85 | handle_description.pin_virt_address = 0; | ||
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | bool NvMap::TryRemoveHandle(const Handle& handle_description) { | 89 | bool NvMap::TryRemoveHandle(const Handle& handle_description) { |
| @@ -123,41 +124,16 @@ std::shared_ptr<NvMap::Handle> NvMap::GetHandle(Handle::Id handle) { | |||
| 123 | } | 124 | } |
| 124 | } | 125 | } |
| 125 | 126 | ||
| 126 | VAddr NvMap::GetHandleAddress(Handle::Id handle) { | 127 | DAddr NvMap::GetHandleAddress(Handle::Id handle) { |
| 127 | std::scoped_lock lock(handles_lock); | 128 | std::scoped_lock lock(handles_lock); |
| 128 | try { | 129 | try { |
| 129 | return handles.at(handle)->address; | 130 | return handles.at(handle)->d_address; |
| 130 | } catch (std::out_of_range&) { | 131 | } catch (std::out_of_range&) { |
| 131 | return 0; | 132 | return 0; |
| 132 | } | 133 | } |
| 133 | } | 134 | } |
| 134 | 135 | ||
| 135 | NvResult NvMap::AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id) { | 136 | DAddr NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id, bool low_area_pin) { |
| 136 | auto handle_description{GetHandle(handle)}; | ||
| 137 | if (!handle_description) [[unlikely]] { | ||
| 138 | return NvResult::BadParameter; | ||
| 139 | } | ||
| 140 | |||
| 141 | if (handle_description->allocated) [[unlikely]] { | ||
| 142 | return NvResult::InsufficientMemory; | ||
| 143 | } | ||
| 144 | |||
| 145 | std::scoped_lock lock(handle_description->mutex); | ||
| 146 | NvResult result = handle_description->Alloc(pFlags, pAlign, pKind, pAddress); | ||
| 147 | if (result != NvResult::Success) { | ||
| 148 | return result; | ||
| 149 | } | ||
| 150 | auto& smmu = host1x.MemoryManager(); | ||
| 151 | size_t total_size = static_cast<size_t>(handle_description->aligned_size); | ||
| 152 | handle_description->d_address = smmu.Allocate(total_size); | ||
| 153 | if (handle_description->d_address == 0) { | ||
| 154 | return NvResult::InsufficientMemory; | ||
| 155 | } | ||
| 156 | smmu.Map(handle_description->d_address, handle_description->address, total_size, session_id); | ||
| 157 | return NvResult::Success; | ||
| 158 | } | ||
| 159 | |||
| 160 | u32 NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id) { | ||
| 161 | auto handle_description{GetHandle(handle)}; | 137 | auto handle_description{GetHandle(handle)}; |
| 162 | if (!handle_description) [[unlikely]] { | 138 | if (!handle_description) [[unlikely]] { |
| 163 | return 0; | 139 | return 0; |
| @@ -176,35 +152,38 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle, size_t session_id) { | |||
| 176 | handle_description->unmap_queue_entry.reset(); | 152 | handle_description->unmap_queue_entry.reset(); |
| 177 | 153 | ||
| 178 | handle_description->pins++; | 154 | handle_description->pins++; |
| 179 | return handle_description->pin_virt_address; | 155 | return handle_description->d_address; |
| 180 | } | 156 | } |
| 181 | } | 157 | } |
| 182 | 158 | ||
| 159 | using namespace std::placeholders; | ||
| 183 | // If not then allocate some space and map it | 160 | // If not then allocate some space and map it |
| 184 | DAddr address{}; | 161 | DAddr address{}; |
| 185 | auto& smmu = host1x.MemoryManager(); | 162 | auto& smmu = host1x.MemoryManager(); |
| 186 | while ((address = smmu.AllocatePinned( | 163 | auto allocate = std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); |
| 187 | static_cast<size_t>(handle_description->aligned_size))) == 0) { | 164 | //: std::bind(&Tegra::MaxwellDeviceMemoryManager::Allocate, &smmu, _1); |
| 165 | while ((address = allocate(static_cast<size_t>(handle_description->aligned_size))) == 0) { | ||
| 188 | // Free handles until the allocation succeeds | 166 | // Free handles until the allocation succeeds |
| 189 | std::scoped_lock queueLock(unmap_queue_lock); | 167 | std::scoped_lock queueLock(unmap_queue_lock); |
| 190 | if (auto freeHandleDesc{unmap_queue.front()}) { | 168 | if (auto freeHandleDesc{unmap_queue.front()}) { |
| 191 | // Handles in the unmap queue are guaranteed not to be pinned so don't bother | 169 | // Handles in the unmap queue are guaranteed not to be pinned so don't bother |
| 192 | // checking if they are before unmapping | 170 | // checking if they are before unmapping |
| 193 | std::scoped_lock freeLock(freeHandleDesc->mutex); | 171 | std::scoped_lock freeLock(freeHandleDesc->mutex); |
| 194 | if (handle_description->pin_virt_address) | 172 | if (handle_description->d_address) |
| 195 | UnmapHandle(*freeHandleDesc); | 173 | UnmapHandle(*freeHandleDesc); |
| 196 | } else { | 174 | } else { |
| 197 | LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); | 175 | LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); |
| 198 | } | 176 | } |
| 199 | } | 177 | } |
| 200 | 178 | ||
| 179 | handle_description->d_address = address; | ||
| 180 | |||
| 201 | smmu.Map(address, handle_description->address, handle_description->aligned_size, | 181 | smmu.Map(address, handle_description->address, handle_description->aligned_size, |
| 202 | session_id); | 182 | session_id); |
| 203 | handle_description->pin_virt_address = static_cast<u32>(address); | ||
| 204 | } | 183 | } |
| 205 | 184 | ||
| 206 | handle_description->pins++; | 185 | handle_description->pins++; |
| 207 | return handle_description->pin_virt_address; | 186 | return handle_description->d_address; |
| 208 | } | 187 | } |
| 209 | 188 | ||
| 210 | void NvMap::UnpinHandle(Handle::Id handle) { | 189 | void NvMap::UnpinHandle(Handle::Id handle) { |
| @@ -255,15 +234,10 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna | |||
| 255 | LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); | 234 | LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); |
| 256 | } else if (handle_description->dupes == 0) { | 235 | } else if (handle_description->dupes == 0) { |
| 257 | // Force unmap the handle | 236 | // Force unmap the handle |
| 258 | if (handle_description->pin_virt_address) { | 237 | if (handle_description->d_address) { |
| 259 | std::scoped_lock queueLock(unmap_queue_lock); | 238 | std::scoped_lock queueLock(unmap_queue_lock); |
| 260 | UnmapHandle(*handle_description); | 239 | UnmapHandle(*handle_description); |
| 261 | } | 240 | } |
| 262 | if (handle_description->allocated) { | ||
| 263 | auto& smmu = host1x.MemoryManager(); | ||
| 264 | smmu.Free(handle_description->d_address, handle_description->aligned_size); | ||
| 265 | smmu.Unmap(handle_description->d_address, handle_description->aligned_size); | ||
| 266 | } | ||
| 267 | 241 | ||
| 268 | handle_description->pins = 0; | 242 | handle_description->pins = 0; |
| 269 | } | 243 | } |
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: | |||
| 48 | using Id = u32; | 48 | using Id = u32; |
| 49 | Id id; //!< A globally unique identifier for this handle | 49 | Id id; //!< A globally unique identifier for this handle |
| 50 | 50 | ||
| 51 | s32 pins{}; | 51 | s64 pins{}; |
| 52 | u32 pin_virt_address{}; | 52 | u32 pin_virt_address{}; |
| 53 | std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{}; | 53 | std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{}; |
| 54 | 54 | ||
| @@ -63,15 +63,14 @@ public: | |||
| 63 | 63 | ||
| 64 | VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, | 64 | VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, |
| 65 | //!< this can also be in the nvdrv tmem | 65 | //!< this can also be in the nvdrv tmem |
| 66 | DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, | ||
| 67 | //!< this can also be in the nvdrv tmem | ||
| 68 | bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC | 66 | bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC |
| 69 | //!< call | 67 | //!< call |
| 70 | 68 | ||
| 71 | u8 kind{}; //!< Used for memory compression | 69 | u8 kind{}; //!< Used for memory compression |
| 72 | bool allocated{}; //!< If the handle has been allocated with `Alloc` | 70 | bool allocated{}; //!< If the handle has been allocated with `Alloc` |
| 73 | 71 | ||
| 74 | u64 dma_map_addr{}; //! remove me after implementing pinning. | 72 | DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, |
| 73 | //!< this can also be in the nvdrv tmem | ||
| 75 | 74 | ||
| 76 | Handle(u64 size, Id id); | 75 | Handle(u64 size, Id id); |
| 77 | 76 | ||
| @@ -119,15 +118,7 @@ public: | |||
| 119 | 118 | ||
| 120 | std::shared_ptr<Handle> GetHandle(Handle::Id handle); | 119 | std::shared_ptr<Handle> GetHandle(Handle::Id handle); |
| 121 | 120 | ||
| 122 | VAddr GetHandleAddress(Handle::Id handle); | 121 | DAddr GetHandleAddress(Handle::Id handle); |
| 123 | |||
| 124 | /** | ||
| 125 | * @brief Maps a handle into the SMMU address space | ||
| 126 | * @note This operation is refcounted, the number of calls to this must eventually match the | ||
| 127 | * number of calls to `UnpinHandle` | ||
| 128 | * @return The SMMU virtual address that the handle has been mapped to | ||
| 129 | */ | ||
| 130 | u32 PinHandle(Handle::Id handle, size_t session_id); | ||
| 131 | 122 | ||
| 132 | /** | 123 | /** |
| 133 | * @brief Maps a handle into the SMMU address space | 124 | * @brief Maps a handle into the SMMU address space |
| @@ -135,7 +126,7 @@ public: | |||
| 135 | * number of calls to `UnpinHandle` | 126 | * number of calls to `UnpinHandle` |
| 136 | * @return The SMMU virtual address that the handle has been mapped to | 127 | * @return The SMMU virtual address that the handle has been mapped to |
| 137 | */ | 128 | */ |
| 138 | NvResult AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id); | 129 | DAddr PinHandle(Handle::Id handle, size_t session_id, bool low_area_pin); |
| 139 | 130 | ||
| 140 | /** | 131 | /** |
| 141 | * @brief When this has been called an equal number of times to `PinHandle` for the supplied | 132 | * @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 | |||
| 42 | u32 height, u32 stride, android::BufferTransformFlags transform, | 42 | u32 height, u32 stride, android::BufferTransformFlags transform, |
| 43 | const Common::Rectangle<int>& crop_rect, | 43 | const Common::Rectangle<int>& crop_rect, |
| 44 | std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) { | 44 | std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) { |
| 45 | const VAddr addr = nvmap.GetHandleAddress(buffer_handle); | 45 | const DAddr addr = nvmap.GetHandleAddress(buffer_handle); |
| 46 | LOG_TRACE(Service, | 46 | LOG_TRACE(Service, |
| 47 | "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", | 47 | "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", |
| 48 | addr, offset, width, height, stride, format); | 48 | 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<const u8> i | |||
| 40 | case 0x3: | 40 | case 0x3: |
| 41 | return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output); | 41 | return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output); |
| 42 | case 0x5: | 42 | case 0x5: |
| 43 | return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output); | 43 | return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output, fd); |
| 44 | case 0x6: | 44 | case 0x6: |
| 45 | return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output); | 45 | return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output, fd); |
| 46 | case 0x8: | 46 | case 0x8: |
| 47 | return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output); | 47 | return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output); |
| 48 | case 0x9: | 48 | case 0x9: |
| 49 | return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output); | 49 | return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output); |
| 50 | case 0x14: | 50 | case 0x14: |
| 51 | return WrapVariable(this, &nvhost_as_gpu::Remap, input, output); | 51 | return WrapVariable(this, &nvhost_as_gpu::Remap, input, output, fd); |
| 52 | default: | 52 | default: |
| 53 | break; | 53 | break; |
| 54 | } | 54 | } |
| @@ -86,8 +86,15 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i | |||
| 86 | return NvResult::NotImplemented; | 86 | return NvResult::NotImplemented; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {} | 89 | void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) { |
| 90 | void nvhost_as_gpu::OnClose(DeviceFD fd) {} | 90 | sessions[fd] = session_id; |
| 91 | } | ||
| 92 | void nvhost_as_gpu::OnClose(DeviceFD fd) { | ||
| 93 | auto it = sessions.find(fd); | ||
| 94 | if (it != sessions.end()) { | ||
| 95 | sessions.erase(it); | ||
| 96 | } | ||
| 97 | } | ||
| 91 | 98 | ||
| 92 | NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { | 99 | NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { |
| 93 | LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); | 100 | 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) { | |||
| 206 | static_cast<u32>(aligned_size >> page_size_bits)); | 213 | static_cast<u32>(aligned_size >> page_size_bits)); |
| 207 | } | 214 | } |
| 208 | 215 | ||
| 216 | nvmap.UnpinHandle(mapping->handle); | ||
| 217 | |||
| 209 | // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state | 218 | // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state |
| 210 | // Only FreeSpace can unmap them fully | 219 | // Only FreeSpace can unmap them fully |
| 211 | if (mapping->sparse_alloc) { | 220 | if (mapping->sparse_alloc) { |
| @@ -259,7 +268,7 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) { | |||
| 259 | return NvResult::Success; | 268 | return NvResult::Success; |
| 260 | } | 269 | } |
| 261 | 270 | ||
| 262 | NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) { | 271 | NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries, DeviceFD fd) { |
| 263 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size()); | 272 | LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size()); |
| 264 | 273 | ||
| 265 | if (!vm.initialised) { | 274 | if (!vm.initialised) { |
| @@ -293,19 +302,19 @@ NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) { | |||
| 293 | return NvResult::BadValue; | 302 | return NvResult::BadValue; |
| 294 | } | 303 | } |
| 295 | 304 | ||
| 296 | VAddr cpu_address{static_cast<VAddr>( | 305 | DAddr base = nvmap.PinHandle(entry.handle, sessions[fd], false); |
| 297 | handle->address + | 306 | DAddr device_address{static_cast<DAddr>( |
| 298 | (static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; | 307 | base + (static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; |
| 299 | 308 | ||
| 300 | gmmu->Map(virtual_address, cpu_address, size, static_cast<Tegra::PTEKind>(entry.kind), | 309 | gmmu->Map(virtual_address, device_address, size, |
| 301 | use_big_pages); | 310 | static_cast<Tegra::PTEKind>(entry.kind), use_big_pages); |
| 302 | } | 311 | } |
| 303 | } | 312 | } |
| 304 | 313 | ||
| 305 | return NvResult::Success; | 314 | return NvResult::Success; |
| 306 | } | 315 | } |
| 307 | 316 | ||
| 308 | NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { | 317 | NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd) { |
| 309 | LOG_DEBUG(Service_NVDRV, | 318 | LOG_DEBUG(Service_NVDRV, |
| 310 | "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" | 319 | "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" |
| 311 | ", offset={}", | 320 | ", offset={}", |
| @@ -331,9 +340,9 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { | |||
| 331 | } | 340 | } |
| 332 | 341 | ||
| 333 | u64 gpu_address{static_cast<u64>(params.offset + params.buffer_offset)}; | 342 | u64 gpu_address{static_cast<u64>(params.offset + params.buffer_offset)}; |
| 334 | VAddr cpu_address{mapping->ptr + params.buffer_offset}; | 343 | VAddr device_address{mapping->ptr + params.buffer_offset}; |
| 335 | 344 | ||
| 336 | gmmu->Map(gpu_address, cpu_address, params.mapping_size, | 345 | gmmu->Map(gpu_address, device_address, params.mapping_size, |
| 337 | static_cast<Tegra::PTEKind>(params.kind), mapping->big_page); | 346 | static_cast<Tegra::PTEKind>(params.kind), mapping->big_page); |
| 338 | 347 | ||
| 339 | return NvResult::Success; | 348 | return NvResult::Success; |
| @@ -349,7 +358,8 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { | |||
| 349 | return NvResult::BadValue; | 358 | return NvResult::BadValue; |
| 350 | } | 359 | } |
| 351 | 360 | ||
| 352 | VAddr cpu_address{static_cast<VAddr>(handle->address + params.buffer_offset)}; | 361 | DAddr device_address{static_cast<DAddr>(nvmap.PinHandle(params.handle, sessions[fd], false) + |
| 362 | params.buffer_offset)}; | ||
| 353 | u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; | 363 | u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; |
| 354 | 364 | ||
| 355 | bool big_page{[&]() { | 365 | bool big_page{[&]() { |
| @@ -373,15 +383,14 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { | |||
| 373 | } | 383 | } |
| 374 | 384 | ||
| 375 | const bool use_big_pages = alloc->second.big_pages && big_page; | 385 | const bool use_big_pages = alloc->second.big_pages && big_page; |
| 376 | gmmu->Map(params.offset, cpu_address, size, static_cast<Tegra::PTEKind>(params.kind), | 386 | gmmu->Map(params.offset, device_address, size, static_cast<Tegra::PTEKind>(params.kind), |
| 377 | use_big_pages); | 387 | use_big_pages); |
| 378 | 388 | ||
| 379 | auto mapping{std::make_shared<Mapping>(cpu_address, params.offset, size, true, | 389 | auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size, |
| 380 | use_big_pages, alloc->second.sparse)}; | 390 | true, use_big_pages, alloc->second.sparse)}; |
| 381 | alloc->second.mappings.push_back(mapping); | 391 | alloc->second.mappings.push_back(mapping); |
| 382 | mapping_map[params.offset] = mapping; | 392 | mapping_map[params.offset] = mapping; |
| 383 | } else { | 393 | } else { |
| 384 | |||
| 385 | auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; | 394 | auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; |
| 386 | u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; | 395 | u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; |
| 387 | u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; | 396 | 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) { | |||
| 394 | return NvResult::InsufficientMemory; | 403 | return NvResult::InsufficientMemory; |
| 395 | } | 404 | } |
| 396 | 405 | ||
| 397 | gmmu->Map(params.offset, cpu_address, Common::AlignUp(size, page_size), | 406 | gmmu->Map(params.offset, device_address, Common::AlignUp(size, page_size), |
| 398 | static_cast<Tegra::PTEKind>(params.kind), big_page); | 407 | static_cast<Tegra::PTEKind>(params.kind), big_page); |
| 399 | 408 | ||
| 400 | auto mapping{ | 409 | auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size, |
| 401 | std::make_shared<Mapping>(cpu_address, params.offset, size, false, big_page, false)}; | 410 | false, big_page, false)}; |
| 402 | mapping_map[params.offset] = mapping; | 411 | mapping_map[params.offset] = mapping; |
| 403 | } | 412 | } |
| 404 | 413 | ||
| 405 | return NvResult::Success; | 414 | return NvResult::Success; |
| 406 | } | 415 | } |
| 407 | 416 | ||
| 408 | NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { | 417 | NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params, DeviceFD fd) { |
| 409 | LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); | 418 | LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); |
| 410 | 419 | ||
| 411 | std::scoped_lock lock(mutex); | 420 | std::scoped_lock lock(mutex); |
| @@ -433,6 +442,8 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { | |||
| 433 | gmmu->Unmap(params.offset, mapping->size); | 442 | gmmu->Unmap(params.offset, mapping->size); |
| 434 | } | 443 | } |
| 435 | 444 | ||
| 445 | nvmap.UnpinHandle(mapping->handle); | ||
| 446 | |||
| 436 | mapping_map.erase(params.offset); | 447 | mapping_map.erase(params.offset); |
| 437 | } catch (const std::out_of_range&) { | 448 | } catch (const std::out_of_range&) { |
| 438 | LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset); | 449 | 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: | |||
| 141 | 141 | ||
| 142 | NvResult AllocAsEx(IoctlAllocAsEx& params); | 142 | NvResult AllocAsEx(IoctlAllocAsEx& params); |
| 143 | NvResult AllocateSpace(IoctlAllocSpace& params); | 143 | NvResult AllocateSpace(IoctlAllocSpace& params); |
| 144 | NvResult Remap(std::span<IoctlRemapEntry> params); | 144 | NvResult Remap(std::span<IoctlRemapEntry> params, DeviceFD fd); |
| 145 | NvResult MapBufferEx(IoctlMapBufferEx& params); | 145 | NvResult MapBufferEx(IoctlMapBufferEx& params, DeviceFD fd); |
| 146 | NvResult UnmapBuffer(IoctlUnmapBuffer& params); | 146 | NvResult UnmapBuffer(IoctlUnmapBuffer& params, DeviceFD fd); |
| 147 | NvResult FreeSpace(IoctlFreeSpace& params); | 147 | NvResult FreeSpace(IoctlFreeSpace& params); |
| 148 | NvResult BindChannel(IoctlBindChannel& params); | 148 | NvResult BindChannel(IoctlBindChannel& params); |
| 149 | 149 | ||
| @@ -159,16 +159,18 @@ private: | |||
| 159 | NvCore::NvMap& nvmap; | 159 | NvCore::NvMap& nvmap; |
| 160 | 160 | ||
| 161 | struct Mapping { | 161 | struct Mapping { |
| 162 | VAddr ptr; | 162 | NvCore::NvMap::Handle::Id handle; |
| 163 | DAddr ptr; | ||
| 163 | u64 offset; | 164 | u64 offset; |
| 164 | u64 size; | 165 | u64 size; |
| 165 | bool fixed; | 166 | bool fixed; |
| 166 | bool big_page; // Only valid if fixed == false | 167 | bool big_page; // Only valid if fixed == false |
| 167 | bool sparse_alloc; | 168 | bool sparse_alloc; |
| 168 | 169 | ||
| 169 | Mapping(VAddr ptr_, u64 offset_, u64 size_, bool fixed_, bool big_page_, bool sparse_alloc_) | 170 | Mapping(NvCore::NvMap::Handle::Id handle_, DAddr ptr_, u64 offset_, u64 size_, bool fixed_, |
| 170 | : ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), big_page(big_page_), | 171 | bool big_page_, bool sparse_alloc_) |
| 171 | sparse_alloc(sparse_alloc_) {} | 172 | : handle(handle_), ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), |
| 173 | big_page(big_page_), sparse_alloc(sparse_alloc_) {} | ||
| 172 | }; | 174 | }; |
| 173 | 175 | ||
| 174 | struct Allocation { | 176 | struct Allocation { |
| @@ -212,9 +214,7 @@ private: | |||
| 212 | bool initialised{}; | 214 | bool initialised{}; |
| 213 | } vm; | 215 | } vm; |
| 214 | std::shared_ptr<Tegra::MemoryManager> gmmu; | 216 | std::shared_ptr<Tegra::MemoryManager> gmmu; |
| 215 | 217 | std::unordered_map<DeviceFD, size_t> sessions; | |
| 216 | // s32 channel{}; | ||
| 217 | // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; | ||
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | } // namespace Service::Nvidia::Devices | 220 | } // 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<u8> data, De | |||
| 95 | offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); | 95 | offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); |
| 96 | 96 | ||
| 97 | auto& gpu = system.GPU(); | 97 | auto& gpu = system.GPU(); |
| 98 | //auto& device_memory = system.Host1x().MemoryManager(); | ||
| 99 | auto* session = core.GetSession(sessions[fd]); | ||
| 100 | |||
| 98 | if (gpu.UseNvdec()) { | 101 | if (gpu.UseNvdec()) { |
| 99 | for (std::size_t i = 0; i < syncpt_increments.size(); i++) { | 102 | for (std::size_t i = 0; i < syncpt_increments.size(); i++) { |
| 100 | const SyncptIncr& syncpt_incr = syncpt_increments[i]; | 103 | const SyncptIncr& syncpt_incr = syncpt_increments[i]; |
| @@ -106,7 +109,7 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De | |||
| 106 | const auto object = nvmap.GetHandle(cmd_buffer.memory_id); | 109 | const auto object = nvmap.GetHandle(cmd_buffer.memory_id); |
| 107 | ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); | 110 | ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); |
| 108 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); | 111 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); |
| 109 | system.ApplicationMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), | 112 | session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), |
| 110 | cmdlist.size() * sizeof(u32)); | 113 | cmdlist.size() * sizeof(u32)); |
| 111 | gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); | 114 | gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); |
| 112 | } | 115 | } |
| @@ -136,7 +139,8 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) { | |||
| 136 | NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd) { | 139 | NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd) { |
| 137 | const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size())); | 140 | const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size())); |
| 138 | for (size_t i = 0; i < num_entries; i++) { | 141 | for (size_t i = 0; i < num_entries; i++) { |
| 139 | entries[i].map_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd]); | 142 | DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, sessions[fd], true); |
| 143 | entries[i].map_address = static_cast<u32>(pin_address); | ||
| 140 | } | 144 | } |
| 141 | 145 | ||
| 142 | return NvResult::Success; | 146 | 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) { | |||
| 123 | return NvResult::InsufficientMemory; | 123 | return NvResult::InsufficientMemory; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | const auto result = file.AllocateHandle(params.handle, params.flags, params.align, params.kind, | 126 | const auto result = |
| 127 | params.address, sessions[fd]); | 127 | handle_description->Alloc(params.flags, params.align, params.kind, params.address); |
| 128 | if (result != NvResult::Success) { | 128 | if (result != NvResult::Success) { |
| 129 | LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); | 129 | LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); |
| 130 | return result; | 130 | 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 @@ | |||
| 13 | #include "core/hle/service/nvdrv/nvdrv.h" | 13 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 14 | #include "core/hle/service/nvdrv/nvdrv_interface.h" | 14 | #include "core/hle/service/nvdrv/nvdrv_interface.h" |
| 15 | 15 | ||
| 16 | #pragma optimize("", off) | ||
| 17 | |||
| 18 | namespace Service::Nvidia { | 16 | namespace Service::Nvidia { |
| 19 | 17 | ||
| 20 | void NVDRV::Open(HLERequestContext& ctx) { | 18 | void NVDRV::Open(HLERequestContext& ctx) { |
| @@ -173,8 +171,8 @@ void NVDRV::Initialize(HLERequestContext& ctx) { | |||
| 173 | [[maybe_unused]] const auto transfer_memory_size = rp.Pop<u32>(); | 171 | [[maybe_unused]] const auto transfer_memory_size = rp.Pop<u32>(); |
| 174 | 172 | ||
| 175 | auto& container = nvdrv->GetContainer(); | 173 | auto& container = nvdrv->GetContainer(); |
| 176 | auto process = ctx.GetObjectFromHandle(process_handle); | 174 | auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle); |
| 177 | session_id = container.OpenSession(process->DynamicCast<Kernel::KProcess*>()); | 175 | session_id = container.OpenSession(process.GetPointerUnsafe()); |
| 178 | 176 | ||
| 179 | is_initialized = true; | 177 | is_initialized = true; |
| 180 | } | 178 | } |
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 @@ | |||
| 24 | #include "core/hle/kernel/k_process.h" | 24 | #include "core/hle/kernel/k_process.h" |
| 25 | #include "core/memory.h" | 25 | #include "core/memory.h" |
| 26 | #include "video_core/gpu.h" | 26 | #include "video_core/gpu.h" |
| 27 | #include "video_core/host1x/gpu_device_memory_manager.h" | ||
| 28 | #include "video_core/host1x/host1x.h" | ||
| 27 | #include "video_core/rasterizer_download_area.h" | 29 | #include "video_core/rasterizer_download_area.h" |
| 28 | 30 | ||
| 29 | namespace Core::Memory { | 31 | namespace Core::Memory { |
| @@ -638,15 +640,16 @@ struct Memory::Impl { | |||
| 638 | base * YUZU_PAGESIZE, (base + size) * YUZU_PAGESIZE); | 640 | base * YUZU_PAGESIZE, (base + size) * YUZU_PAGESIZE); |
| 639 | 641 | ||
| 640 | // During boot, current_page_table might not be set yet, in which case we need not flush | 642 | // During boot, current_page_table might not be set yet, in which case we need not flush |
| 641 | if (system.IsPoweredOn()) { | 643 | /*if (system.IsPoweredOn()) { |
| 642 | auto& gpu = system.GPU(); | 644 | auto& gpu = system.GPU(); |
| 643 | for (u64 i = 0; i < size; i++) { | 645 | for (u64 i = 0; i < size; i++) { |
| 644 | const auto page = base + i; | 646 | const auto page = base + i; |
| 645 | if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) { | 647 | if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) { |
| 648 | |||
| 646 | gpu.FlushAndInvalidateRegion(page << YUZU_PAGEBITS, YUZU_PAGESIZE); | 649 | gpu.FlushAndInvalidateRegion(page << YUZU_PAGEBITS, YUZU_PAGESIZE); |
| 647 | } | 650 | } |
| 648 | } | 651 | } |
| 649 | } | 652 | }*/ |
| 650 | 653 | ||
| 651 | const auto end = base + size; | 654 | const auto end = base + size; |
| 652 | ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", | 655 | ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", |
| @@ -811,10 +814,15 @@ struct Memory::Impl { | |||
| 811 | return true; | 814 | return true; |
| 812 | } | 815 | } |
| 813 | 816 | ||
| 814 | void HandleRasterizerDownload(VAddr address, size_t size) { | 817 | void HandleRasterizerDownload(VAddr v_address, size_t size) { |
| 818 | const auto* p = GetPointerImpl( | ||
| 819 | v_address, []() {}, []() {}); | ||
| 820 | auto& gpu_device_memory = system.Host1x().MemoryManager(); | ||
| 821 | DAddr address = | ||
| 822 | gpu_device_memory.GetAddressFromPAddr(system.DeviceMemory().GetRawPhysicalAddr(p)); | ||
| 815 | const size_t core = system.GetCurrentHostThreadID(); | 823 | const size_t core = system.GetCurrentHostThreadID(); |
| 816 | auto& current_area = rasterizer_read_areas[core]; | 824 | auto& current_area = rasterizer_read_areas[core]; |
| 817 | const VAddr end_address = address + size; | 825 | const DAddr end_address = address + size; |
| 818 | if (current_area.start_address <= address && end_address <= current_area.end_address) | 826 | if (current_area.start_address <= address && end_address <= current_area.end_address) |
| 819 | [[likely]] { | 827 | [[likely]] { |
| 820 | return; | 828 | return; |
| @@ -822,7 +830,10 @@ struct Memory::Impl { | |||
| 822 | current_area = system.GPU().OnCPURead(address, size); | 830 | current_area = system.GPU().OnCPURead(address, size); |
| 823 | } | 831 | } |
| 824 | 832 | ||
| 825 | void HandleRasterizerWrite(VAddr address, size_t size) { | 833 | void HandleRasterizerWrite(VAddr v_address, size_t size) { |
| 834 | const auto* p = GetPointerImpl( | ||
| 835 | v_address, []() {}, []() {}); | ||
| 836 | PAddr address = system.DeviceMemory().GetRawPhysicalAddr(p); | ||
| 826 | constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1; | 837 | constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1; |
| 827 | const size_t core = std::min(system.GetCurrentHostThreadID(), | 838 | const size_t core = std::min(system.GetCurrentHostThreadID(), |
| 828 | sys_core); // any other calls threads go to syscore. | 839 | sys_core); // any other calls threads go to syscore. |
| @@ -836,7 +847,7 @@ struct Memory::Impl { | |||
| 836 | } | 847 | } |
| 837 | }); | 848 | }); |
| 838 | auto& current_area = rasterizer_write_areas[core]; | 849 | auto& current_area = rasterizer_write_areas[core]; |
| 839 | VAddr subaddress = address >> YUZU_PAGEBITS; | 850 | PAddr subaddress = address >> YUZU_PAGEBITS; |
| 840 | bool do_collection = current_area.last_address == subaddress; | 851 | bool do_collection = current_area.last_address == subaddress; |
| 841 | if (!do_collection) [[unlikely]] { | 852 | if (!do_collection) [[unlikely]] { |
| 842 | do_collection = system.GPU().OnCPUWrite(address, size); | 853 | do_collection = system.GPU().OnCPUWrite(address, size); |
| @@ -849,7 +860,7 @@ struct Memory::Impl { | |||
| 849 | } | 860 | } |
| 850 | 861 | ||
| 851 | struct GPUDirtyState { | 862 | struct GPUDirtyState { |
| 852 | VAddr last_address; | 863 | PAddr last_address; |
| 853 | }; | 864 | }; |
| 854 | 865 | ||
| 855 | void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { | 866 | 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: | |||
| 498 | std::unique_ptr<Impl> impl; | 498 | std::unique_ptr<Impl> impl; |
| 499 | }; | 499 | }; |
| 500 | 500 | ||
| 501 | enum GuestMemoryFlags : u32 { | ||
| 502 | Read = 1 << 0, | ||
| 503 | Write = 1 << 1, | ||
| 504 | Safe = 1 << 2, | ||
| 505 | Cached = 1 << 3, | ||
| 506 | |||
| 507 | SafeRead = Read | Safe, | ||
| 508 | SafeWrite = Write | Safe, | ||
| 509 | SafeReadWrite = SafeRead | SafeWrite, | ||
| 510 | SafeReadCachedWrite = SafeReadWrite | Cached, | ||
| 511 | |||
| 512 | UnsafeRead = Read, | ||
| 513 | UnsafeWrite = Write, | ||
| 514 | UnsafeReadWrite = UnsafeRead | UnsafeWrite, | ||
| 515 | UnsafeReadCachedWrite = UnsafeReadWrite | Cached, | ||
| 516 | }; | ||
| 517 | |||
| 518 | namespace { | ||
| 519 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 520 | class GuestMemory { | ||
| 521 | using iterator = T*; | ||
| 522 | using const_iterator = const T*; | ||
| 523 | using value_type = T; | ||
| 524 | using element_type = T; | ||
| 525 | using iterator_category = std::contiguous_iterator_tag; | ||
| 526 | |||
| 527 | public: | ||
| 528 | GuestMemory() = delete; | ||
| 529 | explicit GuestMemory(M& memory, u64 addr, std::size_t size, | ||
| 530 | Common::ScratchBuffer<T>* backup = nullptr) | ||
| 531 | : m_memory{memory}, m_addr{addr}, m_size{size} { | ||
| 532 | static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write); | ||
| 533 | if constexpr (FLAGS & GuestMemoryFlags::Read) { | ||
| 534 | Read(addr, size, backup); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | ~GuestMemory() = default; | ||
| 539 | |||
| 540 | T* data() noexcept { | ||
| 541 | return m_data_span.data(); | ||
| 542 | } | ||
| 543 | |||
| 544 | const T* data() const noexcept { | ||
| 545 | return m_data_span.data(); | ||
| 546 | } | ||
| 547 | |||
| 548 | size_t size() const noexcept { | ||
| 549 | return m_size; | ||
| 550 | } | ||
| 551 | |||
| 552 | size_t size_bytes() const noexcept { | ||
| 553 | return this->size() * sizeof(T); | ||
| 554 | } | ||
| 555 | |||
| 556 | [[nodiscard]] T* begin() noexcept { | ||
| 557 | return this->data(); | ||
| 558 | } | ||
| 559 | |||
| 560 | [[nodiscard]] const T* begin() const noexcept { | ||
| 561 | return this->data(); | ||
| 562 | } | ||
| 563 | |||
| 564 | [[nodiscard]] T* end() noexcept { | ||
| 565 | return this->data() + this->size(); | ||
| 566 | } | ||
| 567 | |||
| 568 | [[nodiscard]] const T* end() const noexcept { | ||
| 569 | return this->data() + this->size(); | ||
| 570 | } | ||
| 571 | |||
| 572 | T& operator[](size_t index) noexcept { | ||
| 573 | return m_data_span[index]; | ||
| 574 | } | ||
| 575 | |||
| 576 | const T& operator[](size_t index) const noexcept { | ||
| 577 | return m_data_span[index]; | ||
| 578 | } | ||
| 579 | |||
| 580 | void SetAddressAndSize(u64 addr, std::size_t size) noexcept { | ||
| 581 | m_addr = addr; | ||
| 582 | m_size = size; | ||
| 583 | m_addr_changed = true; | ||
| 584 | } | ||
| 585 | |||
| 586 | std::span<T> Read(u64 addr, std::size_t size, | ||
| 587 | Common::ScratchBuffer<T>* backup = nullptr) noexcept { | ||
| 588 | m_addr = addr; | ||
| 589 | m_size = size; | ||
| 590 | if (m_size == 0) { | ||
| 591 | m_is_data_copy = true; | ||
| 592 | return {}; | ||
| 593 | } | ||
| 594 | |||
| 595 | if (this->TrySetSpan()) { | ||
| 596 | if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 597 | m_memory.FlushRegion(m_addr, this->size_bytes()); | ||
| 598 | } | ||
| 599 | } else { | ||
| 600 | if (backup) { | ||
| 601 | backup->resize_destructive(this->size()); | ||
| 602 | m_data_span = *backup; | ||
| 603 | } else { | ||
| 604 | m_data_copy.resize(this->size()); | ||
| 605 | m_data_span = std::span(m_data_copy); | ||
| 606 | } | ||
| 607 | m_is_data_copy = true; | ||
| 608 | m_span_valid = true; | ||
| 609 | if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 610 | m_memory.ReadBlock(m_addr, this->data(), this->size_bytes()); | ||
| 611 | } else { | ||
| 612 | m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes()); | ||
| 613 | } | ||
| 614 | } | ||
| 615 | return m_data_span; | ||
| 616 | } | ||
| 617 | |||
| 618 | void Write(std::span<T> write_data) noexcept { | ||
| 619 | if constexpr (FLAGS & GuestMemoryFlags::Cached) { | ||
| 620 | m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes()); | ||
| 621 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 622 | m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes()); | ||
| 623 | } else { | ||
| 624 | m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes()); | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 628 | bool TrySetSpan() noexcept { | ||
| 629 | if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) { | ||
| 630 | m_data_span = {reinterpret_cast<T*>(ptr), this->size()}; | ||
| 631 | m_span_valid = true; | ||
| 632 | return true; | ||
| 633 | } | ||
| 634 | return false; | ||
| 635 | } | ||
| 636 | |||
| 637 | protected: | ||
| 638 | bool IsDataCopy() const noexcept { | ||
| 639 | return m_is_data_copy; | ||
| 640 | } | ||
| 641 | |||
| 642 | bool AddressChanged() const noexcept { | ||
| 643 | return m_addr_changed; | ||
| 644 | } | ||
| 645 | |||
| 646 | M& m_memory; | ||
| 647 | u64 m_addr{}; | ||
| 648 | size_t m_size{}; | ||
| 649 | std::span<T> m_data_span{}; | ||
| 650 | std::vector<T> m_data_copy{}; | ||
| 651 | bool m_span_valid{false}; | ||
| 652 | bool m_is_data_copy{false}; | ||
| 653 | bool m_addr_changed{false}; | ||
| 654 | }; | ||
| 655 | |||
| 656 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 657 | class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> { | ||
| 658 | public: | ||
| 659 | GuestMemoryScoped() = delete; | ||
| 660 | explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size, | ||
| 661 | Common::ScratchBuffer<T>* backup = nullptr) | ||
| 662 | : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) { | ||
| 663 | if constexpr (!(FLAGS & GuestMemoryFlags::Read)) { | ||
| 664 | if (!this->TrySetSpan()) { | ||
| 665 | if (backup) { | ||
| 666 | this->m_data_span = *backup; | ||
| 667 | this->m_span_valid = true; | ||
| 668 | this->m_is_data_copy = true; | ||
| 669 | } | ||
| 670 | } | ||
| 671 | } | ||
| 672 | } | ||
| 673 | |||
| 674 | ~GuestMemoryScoped() { | ||
| 675 | if constexpr (FLAGS & GuestMemoryFlags::Write) { | ||
| 676 | if (this->size() == 0) [[unlikely]] { | ||
| 677 | return; | ||
| 678 | } | ||
| 679 | |||
| 680 | if (this->AddressChanged() || this->IsDataCopy()) { | ||
| 681 | ASSERT(this->m_span_valid); | ||
| 682 | if constexpr (FLAGS & GuestMemoryFlags::Cached) { | ||
| 683 | this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes()); | ||
| 684 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 685 | this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes()); | ||
| 686 | } else { | ||
| 687 | this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes()); | ||
| 688 | } | ||
| 689 | } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) || | ||
| 690 | (FLAGS & GuestMemoryFlags::Cached)) { | ||
| 691 | this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes()); | ||
| 692 | } | ||
| 693 | } | ||
| 694 | } | ||
| 695 | }; | ||
| 696 | } // namespace | ||
| 697 | |||
| 698 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 699 | using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>; | ||
| 700 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 701 | using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>; | ||
| 702 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 703 | using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>; | ||
| 704 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 705 | using GpuGuestMemoryScoped = GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>; | ||
| 706 | } // namespace Core::Memory | 501 | } // namespace Core::Memory |