summaryrefslogtreecommitdiff
path: root/src/common/host_memory.cpp
diff options
context:
space:
mode:
authorGravatar Markus Wick2021-06-05 10:07:26 +0200
committerGravatar Markus Wick2021-06-11 17:27:06 +0200
commit5105318bbc6843de14f3f949515007d9bf76aa7b (patch)
tree271c02fcc896232da5051b13e5a88ee2d487146f /src/common/host_memory.cpp
parentcommon/host_memory: Add interface and Windows implementation (diff)
downloadyuzu-5105318bbc6843de14f3f949515007d9bf76aa7b.tar.gz
yuzu-5105318bbc6843de14f3f949515007d9bf76aa7b.tar.xz
yuzu-5105318bbc6843de14f3f949515007d9bf76aa7b.zip
common/host_memory: Add Linux implementation
Diffstat (limited to 'src/common/host_memory.cpp')
-rw-r--r--src/common/host_memory.cpp130
1 files changed, 120 insertions, 10 deletions
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 4f5086e90..eb50fbd9f 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -1,11 +1,5 @@
1#ifdef __linux__ 1#ifdef _WIN32
2#ifndef _GNU_SOURCE 2
3#define _GNU_SOURCE
4#endif
5#include <fcntl.h>
6#include <sys/mman.h>
7#include <unistd.h>
8#elif defined(_WIN32) // ^^^ Linux ^^^ vvv Windows vvv
9#ifdef _WIN32_WINNT 3#ifdef _WIN32_WINNT
10#undef _WIN32_WINNT 4#undef _WIN32_WINNT
11#endif 5#endif
@@ -20,13 +14,23 @@
20 14
21#pragma comment(lib, "mincore.lib") 15#pragma comment(lib, "mincore.lib")
22 16
23#endif // ^^^ Windows ^^^ 17#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
18
19#ifndef _GNU_SOURCE
20#define _GNU_SOURCE
21#endif
22#include <fcntl.h>
23#include <sys/mman.h>
24#include <unistd.h>
25
26#endif // ^^^ Linux ^^^
24 27
25#include <mutex> 28#include <mutex>
26 29
27#include "common/assert.h" 30#include "common/assert.h"
28#include "common/host_memory.h" 31#include "common/host_memory.h"
29#include "common/logging/log.h" 32#include "common/logging/log.h"
33#include "common/scope_exit.h"
30 34
31namespace Common { 35namespace Common {
32 36
@@ -269,7 +273,113 @@ private:
269 std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset 273 std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
270}; 274};
271 275
272#else 276#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
277
278class HostMemory::Impl {
279public:
280 explicit Impl(size_t backing_size_, size_t virtual_size_)
281 : backing_size{backing_size_}, virtual_size{virtual_size_} {
282 bool good = false;
283 SCOPE_EXIT({
284 if (!good) {
285 Release();
286 }
287 });
288
289 // Backing memory initialization
290 fd = memfd_create("HostMemory", 0);
291 if (fd == -1) {
292 LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno));
293 throw std::bad_alloc{};
294 }
295
296 // Defined to extend the file with zeros
297 int ret = ftruncate(fd, backing_size);
298 if (ret != 0) {
299 LOG_CRITICAL(HW_Memory, "ftruncate failed with {}, are you out-of-memory?",
300 strerror(errno));
301 throw std::bad_alloc{};
302 }
303
304 backing_base = static_cast<u8*>(
305 mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
306 if (backing_base == MAP_FAILED) {
307 LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
308 throw std::bad_alloc{};
309 }
310
311 // Virtual memory initialization
312 virtual_base = static_cast<u8*>(
313 mmap(nullptr, virtual_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
314 if (virtual_base == MAP_FAILED) {
315 LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
316 throw std::bad_alloc{};
317 }
318
319 good = true;
320 }
321
322 ~Impl() {
323 Release();
324 }
325
326 void Map(size_t virtual_offset, size_t host_offset, size_t length) {
327
328 void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE,
329 MAP_SHARED | MAP_FIXED, fd, host_offset);
330 ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
331 }
332
333 void Unmap(size_t virtual_offset, size_t length) {
334 // The method name is wrong. We're still talking about the virtual range.
335 // We don't want to unmap, we want to reserve this memory.
336
337 void* ret = mmap(virtual_base + virtual_offset, length, PROT_NONE,
338 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
339 ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
340 }
341
342 void Protect(size_t virtual_offset, size_t length, bool read, bool write) {
343 int flags = 0;
344 if (read) {
345 flags |= PROT_READ;
346 }
347 if (write) {
348 flags |= PROT_WRITE;
349 }
350 int ret = mprotect(virtual_base + virtual_offset, length, flags);
351 ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
352 }
353
354 const size_t backing_size; ///< Size of the backing memory in bytes
355 const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
356
357 u8* backing_base{reinterpret_cast<u8*>(MAP_FAILED)};
358 u8* virtual_base{reinterpret_cast<u8*>(MAP_FAILED)};
359
360private:
361 /// Release all resources in the object
362 void Release() {
363 if (virtual_base != MAP_FAILED) {
364 int ret = munmap(virtual_base, virtual_size);
365 ASSERT_MSG(ret == 0, "munmap failed: {}", strerror(errno));
366 }
367
368 if (backing_base != MAP_FAILED) {
369 int ret = munmap(backing_base, backing_size);
370 ASSERT_MSG(ret == 0, "munmap failed: {}", strerror(errno));
371 }
372
373 if (fd != -1) {
374 int ret = close(fd);
375 ASSERT_MSG(ret == 0, "close failed: {}", strerror(errno));
376 }
377 }
378
379 int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
380};
381
382#else // ^^^ Linux ^^^
273 383
274#error Please implement the host memory for your platform 384#error Please implement the host memory for your platform
275 385