summaryrefslogtreecommitdiff
path: root/src/common/host_memory.cpp
diff options
context:
space:
mode:
authorGravatar Liam2023-11-17 20:33:43 +0200
committerGravatar t8952023-11-25 00:46:15 -0500
commit448d4815decea4b3b29c768f3507c240932d1999 (patch)
tree9b5dd15a17b4ac4be1ef5837e29829f360bd13e8 /src/common/host_memory.cpp
parentcommon: Add free region manager (diff)
downloadyuzu-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.cpp60
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
360uint64_t GetRandomU64() {
361 uint64_t ret;
362 ASSERT(getrandom(&ret, sizeof(ret), 0) == 0);
363 return ret;
364}
365
366void* 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
407void* 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
356class HostMemory::Impl { 413class HostMemory::Impl {
357public: 414public:
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{};