summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2022-09-05 17:51:50 -0700
committerGravatar bunnei2022-10-18 19:13:34 -0700
commit345b9e6a08f7ce99bb71f7184157ed0fe22bf27d (patch)
tree0fdc0689d1c8c78753cfc14376ee37bc10cc9b0c /src
parentcore: hle: kernel: k_process: Change Status -> State. (diff)
downloadyuzu-345b9e6a08f7ce99bb71f7184157ed0fe22bf27d.tar.gz
yuzu-345b9e6a08f7ce99bb71f7184157ed0fe22bf27d.tar.xz
yuzu-345b9e6a08f7ce99bb71f7184157ed0fe22bf27d.zip
core: hle: kernel: Add KDynamicPageManager.
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/hle/kernel/k_dynamic_page_manager.h136
2 files changed, 137 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index abeb5859b..2bb4dea6a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -190,6 +190,7 @@ add_library(core STATIC
190 hle/kernel/k_code_memory.h 190 hle/kernel/k_code_memory.h
191 hle/kernel/k_condition_variable.cpp 191 hle/kernel/k_condition_variable.cpp
192 hle/kernel/k_condition_variable.h 192 hle/kernel/k_condition_variable.h
193 hle/kernel/k_dynamic_page_manager.h
193 hle/kernel/k_event.cpp 194 hle/kernel/k_event.cpp
194 hle/kernel/k_event.h 195 hle/kernel/k_event.h
195 hle/kernel/k_handle_table.cpp 196 hle/kernel/k_handle_table.cpp
diff --git a/src/core/hle/kernel/k_dynamic_page_manager.h b/src/core/hle/kernel/k_dynamic_page_manager.h
new file mode 100644
index 000000000..88d53776a
--- /dev/null
+++ b/src/core/hle/kernel/k_dynamic_page_manager.h
@@ -0,0 +1,136 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/alignment.h"
7#include "common/common_types.h"
8#include "core/hle/kernel/k_page_bitmap.h"
9#include "core/hle/kernel/k_spin_lock.h"
10#include "core/hle/kernel/memory_types.h"
11#include "core/hle/kernel/svc_results.h"
12
13namespace Kernel {
14
15class KDynamicPageManager {
16public:
17 class PageBuffer {
18 private:
19 u8 m_buffer[PageSize];
20 };
21 static_assert(sizeof(PageBuffer) == PageSize);
22
23public:
24 KDynamicPageManager() = default;
25
26 template <typename T>
27 T* GetPointer(VAddr addr) {
28 return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
29 }
30
31 template <typename T>
32 const T* GetPointer(VAddr addr) const {
33 return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
34 }
35
36 Result Initialize(VAddr addr, size_t sz) {
37 // We need to have positive size.
38 R_UNLESS(sz > 0, ResultOutOfMemory);
39 m_backing_memory.resize(sz);
40
41 // Calculate management overhead.
42 const size_t management_size =
43 KPageBitmap::CalculateManagementOverheadSize(sz / sizeof(PageBuffer));
44 const size_t allocatable_size = sz - management_size;
45
46 // Set tracking fields.
47 m_address = addr;
48 m_size = Common::AlignDown(allocatable_size, sizeof(PageBuffer));
49 m_count = allocatable_size / sizeof(PageBuffer);
50 R_UNLESS(m_count > 0, ResultOutOfMemory);
51
52 // Clear the management region.
53 u64* management_ptr = GetPointer<u64>(m_address + allocatable_size);
54 std::memset(management_ptr, 0, management_size);
55
56 // Initialize the bitmap.
57 m_page_bitmap.Initialize(management_ptr, m_count);
58
59 // Free the pages to the bitmap.
60 for (size_t i = 0; i < m_count; i++) {
61 // Ensure the freed page is all-zero.
62 std::memset(GetPointer<PageBuffer>(m_address) + i, 0, PageSize);
63
64 // Set the bit for the free page.
65 m_page_bitmap.SetBit(i);
66 }
67
68 return ResultSuccess;
69 }
70
71 VAddr GetAddress() const {
72 return m_address;
73 }
74 size_t GetSize() const {
75 return m_size;
76 }
77 size_t GetUsed() const {
78 return m_used;
79 }
80 size_t GetPeak() const {
81 return m_peak;
82 }
83 size_t GetCount() const {
84 return m_count;
85 }
86
87 PageBuffer* Allocate() {
88 // Take the lock.
89 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
90 KScopedSpinLock lk(m_lock);
91
92 // Find a random free block.
93 s64 soffset = m_page_bitmap.FindFreeBlock(true);
94 if (soffset < 0) [[unlikely]] {
95 return nullptr;
96 }
97
98 const size_t offset = static_cast<size_t>(soffset);
99
100 // Update our tracking.
101 m_page_bitmap.ClearBit(offset);
102 m_peak = std::max(m_peak, (++m_used));
103
104 return GetPointer<PageBuffer>(m_address) + offset;
105 }
106
107 void Free(PageBuffer* pb) {
108 // Ensure all pages in the heap are zero.
109 std::memset(pb, 0, PageSize);
110
111 // Take the lock.
112 // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
113 KScopedSpinLock lk(m_lock);
114
115 // Set the bit for the free page.
116 size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_address) / sizeof(PageBuffer);
117 m_page_bitmap.SetBit(offset);
118
119 // Decrement our used count.
120 --m_used;
121 }
122
123private:
124 KSpinLock m_lock;
125 KPageBitmap m_page_bitmap;
126 size_t m_used{};
127 size_t m_peak{};
128 size_t m_count{};
129 VAddr m_address{};
130 size_t m_size{};
131
132 // TODO(bunnei): Back by host memory until we emulate kernel virtual address space.
133 std::vector<u8> m_backing_memory;
134};
135
136} // namespace Kernel