diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_block.h | 315 |
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 | |||
| 13 | namespace Kernel::Memory { | ||
| 14 | |||
| 15 | enum 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 | }; | ||
| 97 | DECLARE_ENUM_FLAG_OPERATORS(MemoryState); | ||
| 98 | |||
| 99 | static_assert(static_cast<u32>(MemoryState::Free) == 0x00000000); | ||
| 100 | static_assert(static_cast<u32>(MemoryState::Io) == 0x00002001); | ||
| 101 | static_assert(static_cast<u32>(MemoryState::Static) == 0x00042002); | ||
| 102 | static_assert(static_cast<u32>(MemoryState::Code) == 0x00DC7E03); | ||
| 103 | static_assert(static_cast<u32>(MemoryState::CodeData) == 0x03FEBD04); | ||
| 104 | static_assert(static_cast<u32>(MemoryState::Normal) == 0x037EBD05); | ||
| 105 | static_assert(static_cast<u32>(MemoryState::Shared) == 0x00402006); | ||
| 106 | static_assert(static_cast<u32>(MemoryState::AliasCode) == 0x00DD7E08); | ||
| 107 | static_assert(static_cast<u32>(MemoryState::AliasCodeData) == 0x03FFBD09); | ||
| 108 | static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A); | ||
| 109 | static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B); | ||
| 110 | static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C); | ||
| 111 | static_assert(static_cast<u32>(MemoryState::Transfered) == 0x015C3C0D); | ||
| 112 | static_assert(static_cast<u32>(MemoryState::SharedTransfered) == 0x005C380E); | ||
| 113 | static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F); | ||
| 114 | static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010); | ||
| 115 | static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811); | ||
| 116 | static_assert(static_cast<u32>(MemoryState::NonDeviceIpc) == 0x004C2812); | ||
| 117 | static_assert(static_cast<u32>(MemoryState::Kernel) == 0x00002013); | ||
| 118 | static_assert(static_cast<u32>(MemoryState::GeneratedCode) == 0x00402214); | ||
| 119 | static_assert(static_cast<u32>(MemoryState::CodeOut) == 0x00402015); | ||
| 120 | |||
| 121 | enum 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 | }; | ||
| 135 | DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission); | ||
| 136 | |||
| 137 | enum 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 | }; | ||
| 152 | DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute); | ||
| 153 | |||
| 154 | static_assert((static_cast<u8>(MemoryAttribute::Mask) & | ||
| 155 | static_cast<u8>(MemoryAttribute::DontCareMask)) == 0); | ||
| 156 | |||
| 157 | struct 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 | |||
| 196 | class MemoryBlock final { | ||
| 197 | friend class MemoryBlockManager; | ||
| 198 | |||
| 199 | private: | ||
| 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 | |||
| 209 | public: | ||
| 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 | |||
| 220 | public: | ||
| 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 | |||
| 253 | private: | ||
| 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 | }; | ||
| 313 | static_assert(std::is_trivially_destructible<MemoryBlock>::value); | ||
| 314 | |||
| 315 | } // namespace Kernel::Memory | ||