summaryrefslogtreecommitdiff
path: root/src/common/multi_level_page_table.inc
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/multi_level_page_table.inc')
-rw-r--r--src/common/multi_level_page_table.inc83
1 files changed, 83 insertions, 0 deletions
diff --git a/src/common/multi_level_page_table.inc b/src/common/multi_level_page_table.inc
new file mode 100644
index 000000000..a75e61f9d
--- /dev/null
+++ b/src/common/multi_level_page_table.inc
@@ -0,0 +1,83 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#ifdef _WIN32
6#include <windows.h>
7#else
8#include <sys/mman.h>
9#endif
10
11#include "common/assert.h"
12#include "common/multi_level_page_table.h"
13
14namespace Common {
15
16template <typename BaseAddr>
17MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bits_,
18 std::size_t first_level_bits_,
19 std::size_t page_bits_)
20 : address_space_bits{address_space_bits_},
21 first_level_bits{first_level_bits_}, page_bits{page_bits_} {
22 first_level_shift = address_space_bits - first_level_bits;
23 first_level_chunk_size = 1ULL << (first_level_shift - page_bits);
24 alloc_size = (1ULL << (address_space_bits - page_bits)) * sizeof(BaseAddr);
25 std::size_t first_level_size = 1ULL << first_level_bits;
26 first_level_map.resize(first_level_size, nullptr);
27#ifdef _WIN32
28 void* base{VirtualAlloc(nullptr, alloc_size, MEM_RESERVE, PAGE_READWRITE)};
29#else
30 void* base{mmap(nullptr, alloc_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)};
31
32 if (base == MAP_FAILED) {
33 base = nullptr;
34 }
35#endif
36
37 ASSERT(base);
38 base_ptr = reinterpret_cast<BaseAddr*>(base);
39}
40
41template <typename BaseAddr>
42MultiLevelPageTable<BaseAddr>::~MultiLevelPageTable() noexcept {
43 if (!base_ptr) {
44 return;
45 }
46#ifdef _WIN32
47 ASSERT(VirtualFree(base_ptr, 0, MEM_RELEASE));
48#else
49 ASSERT(munmap(base_ptr, alloc_size) == 0);
50#endif
51}
52
53template <typename BaseAddr>
54void MultiLevelPageTable<BaseAddr>::ReserveRange(u64 start, std::size_t size) {
55 const u64 new_start = start >> first_level_shift;
56 const u64 new_end =
57 (start + size + (first_level_chunk_size << page_bits) - 1) >> first_level_shift;
58 for (u64 i = new_start; i <= new_end; i++) {
59 if (!first_level_map[i]) {
60 AllocateLevel(i);
61 }
62 }
63}
64
65template <typename BaseAddr>
66void MultiLevelPageTable<BaseAddr>::AllocateLevel(u64 level) {
67 void* ptr = reinterpret_cast<char*>(base_ptr) + level * first_level_chunk_size;
68#ifdef _WIN32
69 void* base{VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE)};
70#else
71 void* base{mmap(ptr, first_level_chunk_size, PROT_READ | PROT_WRITE,
72 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)};
73
74 if (base == MAP_FAILED) {
75 base = nullptr;
76 }
77#endif
78 ASSERT(base);
79
80 first_level_map[level] = base;
81}
82
83} // namespace Common