diff options
| author | 2023-11-17 20:33:43 +0200 | |
|---|---|---|
| committer | 2023-11-25 00:46:15 -0500 | |
| commit | 448d4815decea4b3b29c768f3507c240932d1999 (patch) | |
| tree | 9b5dd15a17b4ac4be1ef5837e29829f360bd13e8 /src/common/host_memory.cpp | |
| parent | common: Add free region manager (diff) | |
| download | yuzu-448d4815decea4b3b29c768f3507c240932d1999.tar.gz yuzu-448d4815decea4b3b29c768f3507c240932d1999.tar.xz yuzu-448d4815decea4b3b29c768f3507c240932d1999.zip | |
host_memory: ensure map base is between 36 and 39 bits
Diffstat (limited to 'src/common/host_memory.cpp')
| -rw-r--r-- | src/common/host_memory.cpp | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index ba22595e0..41ca12ab0 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -21,12 +21,14 @@ | |||
| 21 | #include <boost/icl/interval_set.hpp> | 21 | #include <boost/icl/interval_set.hpp> |
| 22 | #include <fcntl.h> | 22 | #include <fcntl.h> |
| 23 | #include <sys/mman.h> | 23 | #include <sys/mman.h> |
| 24 | #include <sys/random.h> | ||
| 24 | #include <unistd.h> | 25 | #include <unistd.h> |
| 25 | #include "common/scope_exit.h" | 26 | #include "common/scope_exit.h" |
| 26 | 27 | ||
| 27 | #endif // ^^^ Linux ^^^ | 28 | #endif // ^^^ Linux ^^^ |
| 28 | 29 | ||
| 29 | #include <mutex> | 30 | #include <mutex> |
| 31 | #include <random> | ||
| 30 | 32 | ||
| 31 | #include "common/alignment.h" | 33 | #include "common/alignment.h" |
| 32 | #include "common/assert.h" | 34 | #include "common/assert.h" |
| @@ -353,6 +355,61 @@ private: | |||
| 353 | 355 | ||
| 354 | #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv | 356 | #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv |
| 355 | 357 | ||
| 358 | #ifdef ARCHITECTURE_arm64 | ||
| 359 | |||
| 360 | uint64_t GetRandomU64() { | ||
| 361 | uint64_t ret; | ||
| 362 | ASSERT(getrandom(&ret, sizeof(ret), 0) == 0); | ||
| 363 | return ret; | ||
| 364 | } | ||
| 365 | |||
| 366 | void* ChooseVirtualBase(size_t virtual_size) { | ||
| 367 | constexpr uintptr_t Map39BitSize = (1ULL << 39); | ||
| 368 | constexpr uintptr_t Map36BitSize = (1ULL << 36); | ||
| 369 | |||
| 370 | // Seed the MT with some initial strong randomness. | ||
| 371 | // | ||
| 372 | // This is not a cryptographic application, we just want something more | ||
| 373 | // random than the current time. | ||
| 374 | std::mt19937_64 rng(GetRandomU64()); | ||
| 375 | |||
| 376 | // We want to ensure we are allocating at an address aligned to the L2 block size. | ||
| 377 | // For Qualcomm devices, we must also allocate memory above 36 bits. | ||
| 378 | const size_t lower = Map36BitSize / HugePageSize; | ||
| 379 | const size_t upper = (Map39BitSize - virtual_size) / HugePageSize; | ||
| 380 | const size_t range = upper - lower; | ||
| 381 | |||
| 382 | // Try up to 64 times to allocate memory at random addresses in the range. | ||
| 383 | for (int i = 0; i < 64; i++) { | ||
| 384 | // Calculate a possible location. | ||
| 385 | uintptr_t hint_address = ((rng() % range) + lower) * HugePageSize; | ||
| 386 | |||
| 387 | // Try to map. | ||
| 388 | // Note: we may be able to take advantage of MAP_FIXED_NOREPLACE here. | ||
| 389 | void* map_pointer = | ||
| 390 | mmap(reinterpret_cast<void*>(hint_address), virtual_size, PROT_READ | PROT_WRITE, | ||
| 391 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); | ||
| 392 | |||
| 393 | // If we successfully mapped, we're done. | ||
| 394 | if (reinterpret_cast<uintptr_t>(map_pointer) == hint_address) { | ||
| 395 | return map_pointer; | ||
| 396 | } | ||
| 397 | |||
| 398 | // Unmap if necessary, and try again. | ||
| 399 | if (map_pointer != MAP_FAILED) { | ||
| 400 | munmap(map_pointer, virtual_size); | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | return MAP_FAILED; | ||
| 405 | } | ||
| 406 | #else | ||
| 407 | void* ChooseVirtualBase(size_t virtual_size) { | ||
| 408 | return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, | ||
| 409 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); | ||
| 410 | } | ||
| 411 | #endif | ||
| 412 | |||
| 356 | class HostMemory::Impl { | 413 | class HostMemory::Impl { |
| 357 | public: | 414 | public: |
| 358 | explicit Impl(size_t backing_size_, size_t virtual_size_) | 415 | explicit Impl(size_t backing_size_, size_t virtual_size_) |
| @@ -415,8 +472,7 @@ public: | |||
| 415 | } | 472 | } |
| 416 | } | 473 | } |
| 417 | #else | 474 | #else |
| 418 | virtual_base = static_cast<u8*>(mmap(nullptr, virtual_size, PROT_NONE, | 475 | virtual_base = static_cast<u8*>(ChooseVirtualBase(virtual_size)); |
| 419 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)); | ||
| 420 | if (virtual_base == MAP_FAILED) { | 476 | if (virtual_base == MAP_FAILED) { |
| 421 | LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); | 477 | LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); |
| 422 | throw std::bad_alloc{}; | 478 | throw std::bad_alloc{}; |