diff options
| author | 2021-06-05 10:07:26 +0200 | |
|---|---|---|
| committer | 2021-06-11 17:27:06 +0200 | |
| commit | 5105318bbc6843de14f3f949515007d9bf76aa7b (patch) | |
| tree | 271c02fcc896232da5051b13e5a88ee2d487146f /src/common/host_memory.cpp | |
| parent | common/host_memory: Add interface and Windows implementation (diff) | |
| download | yuzu-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.cpp | 130 |
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 | ||
| 31 | namespace Common { | 35 | namespace 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 | |||
| 278 | class HostMemory::Impl { | ||
| 279 | public: | ||
| 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 | |||
| 360 | private: | ||
| 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 | ||