summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp202
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h79
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp33
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h6
4 files changed, 227 insertions, 93 deletions
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 195421cc0..d4ba88147 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -16,11 +16,12 @@
16#include "video_core/renderer_base.h" 16#include "video_core/renderer_base.h"
17 17
18namespace Service::Nvidia::Devices { 18namespace Service::Nvidia::Devices {
19
19namespace NvErrCodes { 20namespace NvErrCodes {
20enum { 21constexpr u32 Success{};
21 InvalidNmapHandle = -22, 22constexpr u32 OutOfMemory{static_cast<u32>(-12)};
22}; 23constexpr u32 InvalidInput{static_cast<u32>(-22)};
23} 24} // namespace NvErrCodes
24 25
25nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 26nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
26 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 27 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
@@ -49,8 +50,9 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
49 break; 50 break;
50 } 51 }
51 52
52 if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) 53 if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) {
53 return Remap(input, output); 54 return Remap(input, output);
55 }
54 56
55 UNIMPLEMENTED_MSG("Unimplemented ioctl command"); 57 UNIMPLEMENTED_MSG("Unimplemented ioctl command");
56 return 0; 58 return 0;
@@ -59,6 +61,7 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
59u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { 61u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
60 IoctlInitalizeEx params{}; 62 IoctlInitalizeEx params{};
61 std::memcpy(&params, input.data(), input.size()); 63 std::memcpy(&params, input.data(), input.size());
64
62 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); 65 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
63 66
64 return 0; 67 return 0;
@@ -67,53 +70,61 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
67u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { 70u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
68 IoctlAllocSpace params{}; 71 IoctlAllocSpace params{};
69 std::memcpy(&params, input.data(), input.size()); 72 std::memcpy(&params, input.data(), input.size());
73
70 LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, 74 LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages,
71 params.page_size, params.flags); 75 params.page_size, params.flags);
72 76
73 auto& gpu = system.GPU(); 77 const auto size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)};
74 const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)}; 78 if ((params.flags & AddressSpaceFlags::FixedOffset) != AddressSpaceFlags::None) {
75 if (params.flags & 1) { 79 params.offset = *system.GPU().MemoryManager().AllocateFixed(params.offset, size);
76 params.offset = gpu.MemoryManager().AllocateSpace(params.offset, size, 1);
77 } else { 80 } else {
78 params.offset = gpu.MemoryManager().AllocateSpace(size, params.align); 81 params.offset = system.GPU().MemoryManager().Allocate(size, params.align);
82 }
83
84 auto result{NvErrCodes::Success};
85 if (!params.offset) {
86 LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size);
87 result = NvErrCodes::OutOfMemory;
79 } 88 }
80 89
81 std::memcpy(output.data(), &params, output.size()); 90 std::memcpy(output.data(), &params, output.size());
82 return 0; 91 return result;
83} 92}
84 93
85u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 94u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
86 std::size_t num_entries = input.size() / sizeof(IoctlRemapEntry); 95 const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
87 96
88 LOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries); 97 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
89 98
99 auto result{NvErrCodes::Success};
90 std::vector<IoctlRemapEntry> entries(num_entries); 100 std::vector<IoctlRemapEntry> entries(num_entries);
91 std::memcpy(entries.data(), input.data(), input.size()); 101 std::memcpy(entries.data(), input.data(), input.size());
92 102
93 auto& gpu = system.GPU();
94 for (const auto& entry : entries) { 103 for (const auto& entry : entries) {
95 LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", 104 LOG_DEBUG(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
96 entry.offset, entry.nvmap_handle, entry.pages); 105 entry.offset, entry.nvmap_handle, entry.pages);
97 GPUVAddr offset = static_cast<GPUVAddr>(entry.offset) << 0x10; 106
98 auto object = nvmap_dev->GetObject(entry.nvmap_handle); 107 const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
99 if (!object) { 108 if (!object) {
100 LOG_CRITICAL(Service_NVDRV, "nvmap {} is an invalid handle!", entry.nvmap_handle); 109 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
101 std::memcpy(output.data(), entries.data(), output.size()); 110 result = NvErrCodes::InvalidInput;
102 return static_cast<u32>(NvErrCodes::InvalidNmapHandle); 111 break;
103 } 112 }
104 113
105 ASSERT(object->status == nvmap::Object::Status::Allocated); 114 const auto offset{static_cast<GPUVAddr>(entry.offset) << 0x10};
115 const auto size{static_cast<u64>(entry.pages) << 0x10};
116 const auto map_offset{static_cast<u64>(entry.map_offset) << 0x10};
117 const auto addr{system.GPU().MemoryManager().Map(object->addr + map_offset, offset, size)};
106 118
107 const u64 size = static_cast<u64>(entry.pages) << 0x10; 119 if (!addr) {
108 ASSERT(size <= object->size); 120 LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
109 const u64 map_offset = static_cast<u64>(entry.map_offset) << 0x10; 121 result = NvErrCodes::InvalidInput;
110 122 break;
111 const GPUVAddr returned = 123 }
112 gpu.MemoryManager().MapBufferEx(object->addr + map_offset, offset, size);
113 ASSERT(returned == offset);
114 } 124 }
125
115 std::memcpy(output.data(), entries.data(), output.size()); 126 std::memcpy(output.data(), entries.data(), output.size());
116 return 0; 127 return result;
117} 128}
118 129
119u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { 130u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
@@ -126,44 +137,76 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
126 params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size, 137 params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
127 params.offset); 138 params.offset);
128 139
129 if (!params.nvmap_handle) { 140 const auto object{nvmap_dev->GetObject(params.nvmap_handle)};
130 return 0; 141 if (!object) {
142 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
143 std::memcpy(output.data(), &params, output.size());
144 return NvErrCodes::InvalidInput;
131 } 145 }
132 146
133 auto object = nvmap_dev->GetObject(params.nvmap_handle);
134 ASSERT(object);
135
136 // We can only map objects that have already been assigned a CPU address.
137 ASSERT(object->status == nvmap::Object::Status::Allocated);
138
139 ASSERT(params.buffer_offset == 0);
140
141 // The real nvservices doesn't make a distinction between handles and ids, and 147 // The real nvservices doesn't make a distinction between handles and ids, and
142 // object can only have one handle and it will be the same as its id. Assert that this is the 148 // object can only have one handle and it will be the same as its id. Assert that this is the
143 // case to prevent unexpected behavior. 149 // case to prevent unexpected behavior.
144 ASSERT(object->id == params.nvmap_handle); 150 ASSERT(object->id == params.nvmap_handle);
145
146 auto& gpu = system.GPU(); 151 auto& gpu = system.GPU();
147 152
148 if (params.flags & 1) { 153 u64 page_size{params.page_size};
149 params.offset = gpu.MemoryManager().MapBufferEx(object->addr, params.offset, object->size); 154 if (!page_size) {
150 } else { 155 page_size = object->align;
151 params.offset = gpu.MemoryManager().MapBufferEx(object->addr, object->size); 156 }
157
158 if ((params.flags & AddressSpaceFlags::Remap) != AddressSpaceFlags::None) {
159 if (const auto buffer_map{FindBufferMap(params.offset)}; buffer_map) {
160 const auto cpu_addr{static_cast<VAddr>(buffer_map->CpuAddr() + params.buffer_offset)};
161 const auto gpu_addr{static_cast<GPUVAddr>(params.offset + params.buffer_offset)};
162
163 if (!gpu.MemoryManager().Map(cpu_addr, gpu_addr, params.mapping_size)) {
164 LOG_CRITICAL(Service_NVDRV,
165 "remap failed, flags={:X}, nvmap_handle={:X}, buffer_offset={}, "
166 "mapping_size = {}, offset={}",
167 params.flags, params.nvmap_handle, params.buffer_offset,
168 params.mapping_size, params.offset);
169
170 std::memcpy(output.data(), &params, output.size());
171 return NvErrCodes::InvalidInput;
172 }
173
174 std::memcpy(output.data(), &params, output.size());
175 return NvErrCodes::Success;
176 } else {
177 LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);
178
179 std::memcpy(output.data(), &params, output.size());
180 return NvErrCodes::InvalidInput;
181 }
152 } 182 }
153 183
154 // Create a new mapping entry for this operation. 184 // We can only map objects that have already been assigned a CPU address.
155 ASSERT_MSG(buffer_mappings.find(params.offset) == buffer_mappings.end(), 185 ASSERT(object->status == nvmap::Object::Status::Allocated);
156 "Offset is already mapped"); 186
187 const auto physical_address{object->addr + params.buffer_offset};
188 u64 size{params.mapping_size};
189 if (!size) {
190 size = object->size;
191 }
157 192
158 BufferMapping mapping{}; 193 const bool is_alloc{(params.flags & AddressSpaceFlags::FixedOffset) == AddressSpaceFlags::None};
159 mapping.nvmap_handle = params.nvmap_handle; 194 if (is_alloc) {
160 mapping.offset = params.offset; 195 params.offset = gpu.MemoryManager().MapAllocate(physical_address, size, page_size);
161 mapping.size = object->size; 196 } else {
197 params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);
198 }
162 199
163 buffer_mappings[params.offset] = mapping; 200 auto result{NvErrCodes::Success};
201 if (!params.offset) {
202 LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size);
203 result = NvErrCodes::InvalidInput;
204 } else {
205 AddBufferMap(params.offset, size, physical_address, is_alloc);
206 }
164 207
165 std::memcpy(output.data(), &params, output.size()); 208 std::memcpy(output.data(), &params, output.size());
166 return 0; 209 return result;
167} 210}
168 211
169u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 212u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
@@ -172,24 +215,20 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
172 215
173 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); 216 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
174 217
175 const auto itr = buffer_mappings.find(params.offset); 218 if (const auto size{RemoveBufferMap(params.offset)}; size) {
176 if (itr == buffer_mappings.end()) { 219 system.GPU().MemoryManager().Unmap(params.offset, *size);
177 LOG_WARNING(Service_NVDRV, "Tried to unmap an invalid offset 0x{:X}", params.offset); 220 } else {
178 // Hardware tests shows that unmapping an already unmapped buffer always returns successful 221 LOG_ERROR(Service_NVDRV, "invalid offset=0x{:X}", params.offset);
179 // and doesn't fail.
180 return 0;
181 } 222 }
182 223
183 params.offset = system.GPU().MemoryManager().UnmapBuffer(params.offset, itr->second.size);
184 buffer_mappings.erase(itr->second.offset);
185
186 std::memcpy(output.data(), &params, output.size()); 224 std::memcpy(output.data(), &params, output.size());
187 return 0; 225 return NvErrCodes::Success;
188} 226}
189 227
190u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { 228u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
191 IoctlBindChannel params{}; 229 IoctlBindChannel params{};
192 std::memcpy(&params, input.data(), input.size()); 230 std::memcpy(&params, input.data(), input.size());
231
193 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); 232 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
194 233
195 channel = params.fd; 234 channel = params.fd;
@@ -199,6 +238,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou
199u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { 238u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
200 IoctlGetVaRegions params{}; 239 IoctlGetVaRegions params{};
201 std::memcpy(&params, input.data(), input.size()); 240 std::memcpy(&params, input.data(), input.size());
241
202 LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, 242 LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
203 params.buf_size); 243 params.buf_size);
204 244
@@ -210,9 +250,43 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o
210 params.regions[1].offset = 0x04000000; 250 params.regions[1].offset = 0x04000000;
211 params.regions[1].page_size = 0x10000; 251 params.regions[1].page_size = 0x10000;
212 params.regions[1].pages = 0x1bffff; 252 params.regions[1].pages = 0x1bffff;
253
213 // TODO(ogniK): This probably can stay stubbed but should add support way way later 254 // TODO(ogniK): This probably can stay stubbed but should add support way way later
255
214 std::memcpy(output.data(), &params, output.size()); 256 std::memcpy(output.data(), &params, output.size());
215 return 0; 257 return 0;
216} 258}
217 259
260std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const {
261 const auto end{buffer_mappings.upper_bound(gpu_addr)};
262 for (auto iter{buffer_mappings.begin()}; iter != end; ++iter) {
263 if (gpu_addr >= iter->second.StartAddr() && gpu_addr < iter->second.EndAddr()) {
264 return iter->second;
265 }
266 }
267
268 return {};
269}
270
271void nvhost_as_gpu::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
272 bool is_allocated) {
273 buffer_mappings[gpu_addr] = {gpu_addr, size, cpu_addr, is_allocated};
274}
275
276std::optional<std::size_t> nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) {
277 if (const auto iter{buffer_mappings.find(gpu_addr)}; iter != buffer_mappings.end()) {
278 std::size_t size{};
279
280 if (iter->second.IsAllocated()) {
281 size = iter->second.Size();
282 }
283
284 buffer_mappings.erase(iter);
285
286 return size;
287 }
288
289 return {};
290}
291
218} // namespace Service::Nvidia::Devices 292} // namespace Service::Nvidia::Devices
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 f79fcc065..9a0cdff0c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -4,9 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map>
7#include <memory> 8#include <memory>
8#include <unordered_map> 9#include <optional>
9#include <vector> 10#include <vector>
11
12#include "common/common_funcs.h"
10#include "common/common_types.h" 13#include "common/common_types.h"
11#include "common/swap.h" 14#include "common/swap.h"
12#include "core/hle/service/nvdrv/devices/nvdevice.h" 15#include "core/hle/service/nvdrv/devices/nvdevice.h"
@@ -15,6 +18,13 @@ namespace Service::Nvidia::Devices {
15 18
16class nvmap; 19class nvmap;
17 20
21enum class AddressSpaceFlags : u32 {
22 None = 0x0,
23 FixedOffset = 0x1,
24 Remap = 0x100,
25};
26DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags);
27
18class nvhost_as_gpu final : public nvdevice { 28class nvhost_as_gpu final : public nvdevice {
19public: 29public:
20 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 30 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
@@ -25,6 +35,45 @@ public:
25 IoctlVersion version) override; 35 IoctlVersion version) override;
26 36
27private: 37private:
38 class BufferMap final {
39 public:
40 constexpr BufferMap() = default;
41
42 constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
43 : start_addr{start_addr}, end_addr{start_addr + size} {}
44
45 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
46 bool is_allocated)
47 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
48 is_allocated{is_allocated} {}
49
50 constexpr VAddr StartAddr() const {
51 return start_addr;
52 }
53
54 constexpr VAddr EndAddr() const {
55 return end_addr;
56 }
57
58 constexpr std::size_t Size() const {
59 return end_addr - start_addr;
60 }
61
62 constexpr VAddr CpuAddr() const {
63 return cpu_addr;
64 }
65
66 constexpr bool IsAllocated() const {
67 return is_allocated;
68 }
69
70 private:
71 GPUVAddr start_addr{};
72 GPUVAddr end_addr{};
73 VAddr cpu_addr{};
74 bool is_allocated{};
75 };
76
28 enum class IoctlCommand : u32_le { 77 enum class IoctlCommand : u32_le {
29 IocInitalizeExCommand = 0x40284109, 78 IocInitalizeExCommand = 0x40284109,
30 IocAllocateSpaceCommand = 0xC0184102, 79 IocAllocateSpaceCommand = 0xC0184102,
@@ -49,7 +98,7 @@ private:
49 struct IoctlAllocSpace { 98 struct IoctlAllocSpace {
50 u32_le pages; 99 u32_le pages;
51 u32_le page_size; 100 u32_le page_size;
52 u32_le flags; 101 AddressSpaceFlags flags;
53 INSERT_PADDING_WORDS(1); 102 INSERT_PADDING_WORDS(1);
54 union { 103 union {
55 u64_le offset; 104 u64_le offset;
@@ -69,18 +118,18 @@ private:
69 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); 118 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
70 119
71 struct IoctlMapBufferEx { 120 struct IoctlMapBufferEx {
72 u32_le flags; // bit0: fixed_offset, bit2: cacheable 121 AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable
73 u32_le kind; // -1 is default 122 u32_le kind; // -1 is default
74 u32_le nvmap_handle; 123 u32_le nvmap_handle;
75 u32_le page_size; // 0 means don't care 124 u32_le page_size; // 0 means don't care
76 u64_le buffer_offset; 125 s64_le buffer_offset;
77 u64_le mapping_size; 126 u64_le mapping_size;
78 u64_le offset; 127 s64_le offset;
79 }; 128 };
80 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); 129 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
81 130
82 struct IoctlUnmapBuffer { 131 struct IoctlUnmapBuffer {
83 u64_le offset; 132 s64_le offset;
84 }; 133 };
85 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); 134 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
86 135
@@ -106,15 +155,6 @@ private:
106 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, 155 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
107 "IoctlGetVaRegions is incorrect size"); 156 "IoctlGetVaRegions is incorrect size");
108 157
109 struct BufferMapping {
110 u64 offset;
111 u64 size;
112 u32 nvmap_handle;
113 };
114
115 /// Map containing the nvmap object mappings in GPU memory.
116 std::unordered_map<u64, BufferMapping> buffer_mappings;
117
118 u32 channel{}; 158 u32 channel{};
119 159
120 u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); 160 u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
@@ -125,7 +165,14 @@ private:
125 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); 165 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
126 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); 166 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
127 167
168 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
169 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
170 std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
171
128 std::shared_ptr<nvmap> nvmap_dev; 172 std::shared_ptr<nvmap> nvmap_dev;
173
174 // This is expected to be ordered, therefore we must use a map, not unordered_map
175 std::map<GPUVAddr, BufferMap> buffer_mappings;
129}; 176};
130 177
131} // namespace Service::Nvidia::Devices 178} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 8c742316c..9436e16ad 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -18,7 +18,12 @@ enum {
18}; 18};
19} 19}
20 20
21nvmap::nvmap(Core::System& system) : nvdevice(system) {} 21nvmap::nvmap(Core::System& system) : nvdevice(system) {
22 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
23 // represent this.
24 CreateObject(0);
25}
26
22nvmap::~nvmap() = default; 27nvmap::~nvmap() = default;
23 28
24VAddr nvmap::GetObjectAddress(u32 handle) const { 29VAddr nvmap::GetObjectAddress(u32 handle) const {
@@ -50,6 +55,21 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<
50 return 0; 55 return 0;
51} 56}
52 57
58u32 nvmap::CreateObject(u32 size) {
59 // Create a new nvmap object and obtain a handle to it.
60 auto object = std::make_shared<Object>();
61 object->id = next_id++;
62 object->size = size;
63 object->status = Object::Status::Created;
64 object->refcount = 1;
65
66 const u32 handle = next_handle++;
67
68 handles.insert_or_assign(handle, std::move(object));
69
70 return handle;
71}
72
53u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { 73u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
54 IocCreateParams params; 74 IocCreateParams params;
55 std::memcpy(&params, input.data(), sizeof(params)); 75 std::memcpy(&params, input.data(), sizeof(params));
@@ -59,17 +79,8 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
59 LOG_ERROR(Service_NVDRV, "Size is 0"); 79 LOG_ERROR(Service_NVDRV, "Size is 0");
60 return static_cast<u32>(NvErrCodes::InvalidValue); 80 return static_cast<u32>(NvErrCodes::InvalidValue);
61 } 81 }
62 // Create a new nvmap object and obtain a handle to it.
63 auto object = std::make_shared<Object>();
64 object->id = next_id++;
65 object->size = params.size;
66 object->status = Object::Status::Created;
67 object->refcount = 1;
68
69 u32 handle = next_handle++;
70 handles[handle] = std::move(object);
71 82
72 params.handle = handle; 83 params.handle = CreateObject(params.size);
73 84
74 std::memcpy(output.data(), &params, sizeof(params)); 85 std::memcpy(output.data(), &params, sizeof(params));
75 return 0; 86 return 0;
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 73c2e8809..84624be00 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -49,10 +49,10 @@ public:
49 49
50private: 50private:
51 /// Id to use for the next handle that is created. 51 /// Id to use for the next handle that is created.
52 u32 next_handle = 1; 52 u32 next_handle = 0;
53 53
54 /// Id to use for the next object that is created. 54 /// Id to use for the next object that is created.
55 u32 next_id = 1; 55 u32 next_id = 0;
56 56
57 /// Mapping of currently allocated handles to the objects they represent. 57 /// Mapping of currently allocated handles to the objects they represent.
58 std::unordered_map<u32, std::shared_ptr<Object>> handles; 58 std::unordered_map<u32, std::shared_ptr<Object>> handles;
@@ -119,6 +119,8 @@ private:
119 }; 119 };
120 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 120 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
121 121
122 u32 CreateObject(u32 size);
123
122 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); 124 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
123 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); 125 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
124 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); 126 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);