summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2023-12-25 07:32:16 +0100
committerGravatar Liam2024-01-18 21:12:30 -0500
commit0a2536a0df1f4aea406f2132d3edda0430acc9d1 (patch)
treec0ad53890581c9c7e180c5ccb3b66e3c63e3ba64 /src/core
parentSMMU: Implement backing CPU page protect/unprotect (diff)
downloadyuzu-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.txt2
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/core.h2
-rw-r--r--src/core/device_memory_manager.h43
-rw-r--r--src/core/device_memory_manager.inc72
-rw-r--r--src/core/gpu_dirty_memory_manager.h10
-rw-r--r--src/core/guest_memory.h218
-rw-r--r--src/core/hle/service/hle_ipc.cpp61
-rw-r--r--src/core/hle/service/hle_ipc.h9
-rw-r--r--src/core/hle/service/nvdrv/core/nvmap.cpp64
-rw-r--r--src/core/hle/service/nvdrv/core/nvmap.h19
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp57
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp6
-rw-r--r--src/core/memory.cpp25
-rw-r--r--src/core/memory.h205
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
654void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { 654void 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
65private: 92private:
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>
105DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_) 105DeviceMemoryManager<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
163template <typename Traits> 163template <typename Traits>
164void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) { 164void 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
179template <typename Traits> 179template <typename Traits>
@@ -256,6 +256,45 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
256 256
257template <typename Traits> 257template <typename Traits>
258void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, size_t size) { 258void 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
277template <typename Traits>
278void 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
296template <typename Traits>
297void 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
276template <typename Traits> 315template <typename Traits>
277void DeviceMemoryManager<Traits>::WriteBlock(DAddr address, void* src_pointer, size_t size) { 316void 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
314template <typename Traits> 354template <typename Traits>
315void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { 355void 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
15namespace Core::Memory {
16
17enum 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
34namespace {
35template <typename M, typename T, GuestMemoryFlags FLAGS>
36class 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
43public:
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
153protected:
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
172template <typename M, typename T, GuestMemoryFlags FLAGS>
173class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
174public:
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
213template <typename T, GuestMemoryFlags FLAGS>
214using CpuGuestMemory = GuestMemory<Core::Memory::Memory, T, FLAGS>;
215template <typename T, GuestMemoryFlags FLAGS>
216using 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"
26namespace {
27static thread_local std::array read_buffer_data_a{
28 Common::ScratchBuffer<u8>(),
29 Common::ScratchBuffer<u8>(),
30 Common::ScratchBuffer<u8>(),
31};
32static 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
39namespace Service { 27namespace Service {
40 28
@@ -343,48 +331,27 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons
343} 331}
344 332
345std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const { 333std::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
361std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const { 343std::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
377std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { 353std::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
25union Result; 23union 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
20NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { 22NvResult 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
88bool NvMap::TryRemoveHandle(const Handle& handle_description) { 89bool 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
126VAddr NvMap::GetHandleAddress(Handle::Id handle) { 127DAddr 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
135NvResult NvMap::AllocateHandle(Handle::Id handle, Handle::Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, size_t session_id) { 136DAddr 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
160u32 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
210void NvMap::UnpinHandle(Handle::Id handle) { 189void 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
89void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {} 89void nvhost_as_gpu::OnOpen(size_t session_id, DeviceFD fd) {
90void nvhost_as_gpu::OnClose(DeviceFD fd) {} 90 sessions[fd] = session_id;
91}
92void 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
92NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { 99NvResult 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
262NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) { 271NvResult 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
308NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { 317NvResult 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
408NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { 417NvResult 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) {
136NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd) { 139NvResult 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
18namespace Service::Nvidia { 16namespace Service::Nvidia {
19 17
20void NVDRV::Open(HLERequestContext& ctx) { 18void 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
29namespace Core::Memory { 31namespace 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
501enum 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
518namespace {
519template <typename M, typename T, GuestMemoryFlags FLAGS>
520class 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
527public:
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
637protected:
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
656template <typename M, typename T, GuestMemoryFlags FLAGS>
657class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
658public:
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
698template <typename T, GuestMemoryFlags FLAGS>
699using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>;
700template <typename T, GuestMemoryFlags FLAGS>
701using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>;
702template <typename T, GuestMemoryFlags FLAGS>
703using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>;
704template <typename T, GuestMemoryFlags FLAGS>
705using GpuGuestMemoryScoped = GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>;
706} // namespace Core::Memory 501} // namespace Core::Memory