summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2020-04-05 14:45:58 -0400
committerGravatar bunnei2020-04-17 00:59:29 -0400
commitc2f4dcb1e3ddca062a51cad11e6314196d9d16bc (patch)
tree8b4edd160c2577ce301ce54872ec69b53c9ab9f8
parentkernel: memory: Add memory_types.h, for things that are commonly used in memo... (diff)
downloadyuzu-c2f4dcb1e3ddca062a51cad11e6314196d9d16bc.tar.gz
yuzu-c2f4dcb1e3ddca062a51cad11e6314196d9d16bc.tar.xz
yuzu-c2f4dcb1e3ddca062a51cad11e6314196d9d16bc.zip
kernel: memory: Add MemoryBlock class, for managing memory blocks and their state.
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/hle/kernel/memory/memory_block.h315
2 files changed, 316 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 6875cff27..504ee2777 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -156,6 +156,7 @@ add_library(core STATIC
156 hle/kernel/kernel.h 156 hle/kernel/kernel.h
157 hle/kernel/memory/address_space_info.cpp 157 hle/kernel/memory/address_space_info.cpp
158 hle/kernel/memory/address_space_info.h 158 hle/kernel/memory/address_space_info.h
159 hle/kernel/memory/memory_block.h
159 hle/kernel/memory/memory_types.h 160 hle/kernel/memory/memory_types.h
160 hle/kernel/memory/slab_heap.h 161 hle/kernel/memory/slab_heap.h
161 hle/kernel/mutex.cpp 162 hle/kernel/mutex.cpp
diff --git a/src/core/hle/kernel/memory/memory_block.h b/src/core/hle/kernel/memory/memory_block.h
new file mode 100644
index 000000000..1bb31405a
--- /dev/null
+++ b/src/core/hle/kernel/memory/memory_block.h
@@ -0,0 +1,315 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/alignment.h"
8#include "common/assert.h"
9#include "common/common_types.h"
10#include "core/hle/kernel/memory/memory_types.h"
11#include "core/hle/kernel/svc_types.h"
12
13namespace Kernel::Memory {
14
15enum class MemoryState : u32 {
16 None = 0,
17 Mask = 0xFFFFFFFF, // TODO(bunnei): This should probable be 0xFF
18 All = ~None,
19
20 FlagCanReprotect = (1 << 8),
21 FlagCanDebug = (1 << 9),
22 FlagCanUseIpc = (1 << 10),
23 FlagCanUseNonDeviceIpc = (1 << 11),
24 FlagCanUseNonSecureIpc = (1 << 12),
25 FlagMapped = (1 << 13),
26 FlagCode = (1 << 14),
27 FlagCanAlias = (1 << 15),
28 FlagCanCodeAlias = (1 << 16),
29 FlagCanTransfer = (1 << 17),
30 FlagCanQueryPhysical = (1 << 18),
31 FlagCanDeviceMap = (1 << 19),
32 FlagCanAlignedDeviceMap = (1 << 20),
33 FlagCanIpcUserBuffer = (1 << 21),
34 FlagReferenceCounted = (1 << 22),
35 FlagCanMapProcess = (1 << 23),
36 FlagCanChangeAttribute = (1 << 24),
37 FlagCanCodeMemory = (1 << 25),
38
39 FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
40 FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical |
41 FlagCanDeviceMap | FlagCanAlignedDeviceMap | FlagCanIpcUserBuffer |
42 FlagReferenceCounted | FlagCanChangeAttribute,
43
44 FlagsCode = FlagCanDebug | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
45 FlagMapped | FlagCode | FlagCanQueryPhysical | FlagCanDeviceMap |
46 FlagCanAlignedDeviceMap | FlagReferenceCounted,
47
48 FlagsMisc = FlagMapped | FlagReferenceCounted | FlagCanQueryPhysical | FlagCanDeviceMap,
49
50 Free = static_cast<u32>(Svc::MemoryState::Free),
51 Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped,
52 Static = static_cast<u32>(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical,
53 Code = static_cast<u32>(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess,
54 CodeData = static_cast<u32>(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess |
55 FlagCanCodeMemory,
56 Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted,
57 Normal = static_cast<u32>(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory,
58
59 AliasCode = static_cast<u32>(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess |
60 FlagCanCodeAlias,
61 AliasCodeData = static_cast<u32>(Svc::MemoryState::AliasCodeData) | FlagsData |
62 FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory,
63
64 Ipc = static_cast<u32>(Svc::MemoryState::Ipc) | FlagsMisc | FlagCanAlignedDeviceMap |
65 FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
66
67 Stack = static_cast<u32>(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap |
68 FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
69
70 ThreadLocal =
71 static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted,
72
73 Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc |
74 FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
75 FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
76
77 SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc |
78 FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
79
80 SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
81 FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
82
83 Inaccessible = static_cast<u32>(Svc::MemoryState::Inaccessible),
84
85 NonSecureIpc = static_cast<u32>(Svc::MemoryState::NonSecureIpc) | FlagsMisc |
86 FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
87
88 NonDeviceIpc =
89 static_cast<u32>(Svc::MemoryState::NonDeviceIpc) | FlagsMisc | FlagCanUseNonDeviceIpc,
90
91 Kernel = static_cast<u32>(Svc::MemoryState::Kernel) | FlagMapped,
92
93 GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped |
94 FlagReferenceCounted | FlagCanDebug,
95 CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted,
96};
97DECLARE_ENUM_FLAG_OPERATORS(MemoryState);
98
99static_assert(static_cast<u32>(MemoryState::Free) == 0x00000000);
100static_assert(static_cast<u32>(MemoryState::Io) == 0x00002001);
101static_assert(static_cast<u32>(MemoryState::Static) == 0x00042002);
102static_assert(static_cast<u32>(MemoryState::Code) == 0x00DC7E03);
103static_assert(static_cast<u32>(MemoryState::CodeData) == 0x03FEBD04);
104static_assert(static_cast<u32>(MemoryState::Normal) == 0x037EBD05);
105static_assert(static_cast<u32>(MemoryState::Shared) == 0x00402006);
106static_assert(static_cast<u32>(MemoryState::AliasCode) == 0x00DD7E08);
107static_assert(static_cast<u32>(MemoryState::AliasCodeData) == 0x03FFBD09);
108static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A);
109static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B);
110static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C);
111static_assert(static_cast<u32>(MemoryState::Transfered) == 0x015C3C0D);
112static_assert(static_cast<u32>(MemoryState::SharedTransfered) == 0x005C380E);
113static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F);
114static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010);
115static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811);
116static_assert(static_cast<u32>(MemoryState::NonDeviceIpc) == 0x004C2812);
117static_assert(static_cast<u32>(MemoryState::Kernel) == 0x00002013);
118static_assert(static_cast<u32>(MemoryState::GeneratedCode) == 0x00402214);
119static_assert(static_cast<u32>(MemoryState::CodeOut) == 0x00402015);
120
121enum class MemoryPermission : u8 {
122 None = 0,
123 Mask = static_cast<u8>(~None),
124
125 Read = 1 << 0,
126 Write = 1 << 1,
127 Execute = 1 << 2,
128
129 ReadAndWrite = Read | Write,
130 ReadAndExecute = Read | Execute,
131
132 UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
133 Svc::MemoryPermission::Execute),
134};
135DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission);
136
137enum class MemoryAttribute : u8 {
138 None = 0x00,
139 Mask = 0x7F,
140 All = Mask,
141 DontCareMask = 0x80,
142
143 Locked = static_cast<u8>(Svc::MemoryAttribute::Locked),
144 IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked),
145 DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared),
146 Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
147
148 IpcAndDeviceMapped = IpcLocked | DeviceShared,
149 LockedAndIpcLocked = Locked | IpcLocked,
150 DeviceSharedAndUncached = DeviceShared | Uncached
151};
152DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute);
153
154static_assert((static_cast<u8>(MemoryAttribute::Mask) &
155 static_cast<u8>(MemoryAttribute::DontCareMask)) == 0);
156
157struct MemoryInfo {
158 VAddr addr{};
159 std::size_t size{};
160 MemoryState state{};
161 MemoryPermission perm{};
162 MemoryAttribute attribute{};
163 MemoryPermission original_perm{};
164 u16 ipc_lock_count{};
165 u16 device_use_count{};
166
167 constexpr Svc::MemoryInfo GetSvcMemoryInfo() const {
168 return {
169 addr,
170 size,
171 static_cast<Svc::MemoryState>(state & MemoryState::Mask),
172 static_cast<Svc::MemoryAttribute>(attribute & MemoryAttribute::Mask),
173 static_cast<Svc::MemoryPermission>(perm & MemoryPermission::UserMask),
174 ipc_lock_count,
175 device_use_count,
176 };
177 }
178
179 constexpr VAddr GetAddress() const {
180 return addr;
181 }
182 constexpr std::size_t GetSize() const {
183 return size;
184 }
185 constexpr std::size_t GetNumPages() const {
186 return GetSize() / PageSize;
187 }
188 constexpr VAddr GetEndAddress() const {
189 return GetAddress() + GetSize();
190 }
191 constexpr VAddr GetLastAddress() const {
192 return GetEndAddress() - 1;
193 }
194};
195
196class MemoryBlock final {
197 friend class MemoryBlockManager;
198
199private:
200 VAddr addr{};
201 std::size_t num_pages{};
202 MemoryState state{MemoryState::None};
203 u16 ipc_lock_count{};
204 u16 device_use_count{};
205 MemoryPermission perm{MemoryPermission::None};
206 MemoryPermission original_perm{MemoryPermission::None};
207 MemoryAttribute attribute{MemoryAttribute::None};
208
209public:
210 static constexpr int Compare(const MemoryBlock& lhs, const MemoryBlock& rhs) {
211 if (lhs.GetAddress() < rhs.GetAddress()) {
212 return -1;
213 } else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
214 return 0;
215 } else {
216 return 1;
217 }
218 }
219
220public:
221 constexpr MemoryBlock() = default;
222 constexpr MemoryBlock(VAddr addr, std::size_t num_pages, MemoryState state,
223 MemoryPermission perm, MemoryAttribute attribute)
224 : addr{addr}, num_pages(num_pages), state{state}, perm{perm}, attribute{attribute} {}
225
226 constexpr VAddr GetAddress() const {
227 return addr;
228 }
229
230 constexpr std::size_t GetNumPages() const {
231 return num_pages;
232 }
233
234 constexpr std::size_t GetSize() const {
235 return GetNumPages() * PageSize;
236 }
237
238 constexpr VAddr GetEndAddress() const {
239 return GetAddress() + GetSize();
240 }
241
242 constexpr VAddr GetLastAddress() const {
243 return GetEndAddress() - 1;
244 }
245
246 constexpr MemoryInfo GetMemoryInfo() const {
247 return {
248 GetAddress(), GetSize(), state, perm,
249 attribute, original_perm, ipc_lock_count, device_use_count,
250 };
251 }
252
253private:
254 constexpr bool HasProperties(MemoryState s, MemoryPermission p, MemoryAttribute a) const {
255 constexpr MemoryAttribute AttributeIgnoreMask{MemoryAttribute::DontCareMask |
256 MemoryAttribute::IpcLocked |
257 MemoryAttribute::DeviceShared};
258 return state == s && perm == p &&
259 (attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask);
260 }
261
262 constexpr bool HasSameProperties(const MemoryBlock& rhs) const {
263 return state == rhs.state && perm == rhs.perm && original_perm == rhs.original_perm &&
264 attribute == rhs.attribute && ipc_lock_count == rhs.ipc_lock_count &&
265 device_use_count == rhs.device_use_count;
266 }
267
268 constexpr bool Contains(VAddr start) const {
269 return GetAddress() <= start && start <= GetEndAddress();
270 }
271
272 constexpr void Add(std::size_t count) {
273 ASSERT(count > 0);
274 ASSERT(GetAddress() + count * PageSize - 1 < GetEndAddress() + count * PageSize - 1);
275
276 num_pages += count;
277 }
278
279 constexpr void Update(MemoryState new_state, MemoryPermission new_perm,
280 MemoryAttribute new_attribute) {
281 ASSERT(original_perm == MemoryPermission::None);
282 ASSERT((attribute & MemoryAttribute::IpcLocked) == MemoryAttribute::None);
283
284 state = new_state;
285 perm = new_perm;
286
287 // TODO(bunnei): Is this right?
288 attribute = static_cast<MemoryAttribute>(
289 new_attribute /*| (attribute & (MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared))*/);
290 }
291
292 constexpr MemoryBlock Split(VAddr split_addr) {
293 ASSERT(GetAddress() < split_addr);
294 ASSERT(Contains(split_addr));
295 ASSERT(Common::IsAligned(split_addr, PageSize));
296
297 MemoryBlock block;
298 block.addr = addr;
299 block.num_pages = (split_addr - GetAddress()) / PageSize;
300 block.state = state;
301 block.ipc_lock_count = ipc_lock_count;
302 block.device_use_count = device_use_count;
303 block.perm = perm;
304 block.original_perm = original_perm;
305 block.attribute = attribute;
306
307 addr = split_addr;
308 num_pages -= block.num_pages;
309
310 return block;
311 }
312};
313static_assert(std::is_trivially_destructible<MemoryBlock>::value);
314
315} // namespace Kernel::Memory