kernel: memory: Add MemoryBlock class, for managing memory blocks and their state.
This commit is contained in:
		| @@ -156,6 +156,7 @@ add_library(core STATIC | ||||
|     hle/kernel/kernel.h | ||||
|     hle/kernel/memory/address_space_info.cpp | ||||
|     hle/kernel/memory/address_space_info.h | ||||
|     hle/kernel/memory/memory_block.h | ||||
|     hle/kernel/memory/memory_types.h | ||||
|     hle/kernel/memory/slab_heap.h | ||||
|     hle/kernel/mutex.cpp | ||||
|   | ||||
							
								
								
									
										315
									
								
								src/core/hle/kernel/memory/memory_block.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								src/core/hle/kernel/memory/memory_block.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,315 @@ | ||||
| // Copyright 2020 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "common/alignment.h" | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/memory/memory_types.h" | ||||
| #include "core/hle/kernel/svc_types.h" | ||||
|  | ||||
| namespace Kernel::Memory { | ||||
|  | ||||
| enum class MemoryState : u32 { | ||||
|     None = 0, | ||||
|     Mask = 0xFFFFFFFF, // TODO(bunnei): This should probable be 0xFF | ||||
|     All = ~None, | ||||
|  | ||||
|     FlagCanReprotect = (1 << 8), | ||||
|     FlagCanDebug = (1 << 9), | ||||
|     FlagCanUseIpc = (1 << 10), | ||||
|     FlagCanUseNonDeviceIpc = (1 << 11), | ||||
|     FlagCanUseNonSecureIpc = (1 << 12), | ||||
|     FlagMapped = (1 << 13), | ||||
|     FlagCode = (1 << 14), | ||||
|     FlagCanAlias = (1 << 15), | ||||
|     FlagCanCodeAlias = (1 << 16), | ||||
|     FlagCanTransfer = (1 << 17), | ||||
|     FlagCanQueryPhysical = (1 << 18), | ||||
|     FlagCanDeviceMap = (1 << 19), | ||||
|     FlagCanAlignedDeviceMap = (1 << 20), | ||||
|     FlagCanIpcUserBuffer = (1 << 21), | ||||
|     FlagReferenceCounted = (1 << 22), | ||||
|     FlagCanMapProcess = (1 << 23), | ||||
|     FlagCanChangeAttribute = (1 << 24), | ||||
|     FlagCanCodeMemory = (1 << 25), | ||||
|  | ||||
|     FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc | | ||||
|                 FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical | | ||||
|                 FlagCanDeviceMap | FlagCanAlignedDeviceMap | FlagCanIpcUserBuffer | | ||||
|                 FlagReferenceCounted | FlagCanChangeAttribute, | ||||
|  | ||||
|     FlagsCode = FlagCanDebug | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc | | ||||
|                 FlagMapped | FlagCode | FlagCanQueryPhysical | FlagCanDeviceMap | | ||||
|                 FlagCanAlignedDeviceMap | FlagReferenceCounted, | ||||
|  | ||||
|     FlagsMisc = FlagMapped | FlagReferenceCounted | FlagCanQueryPhysical | FlagCanDeviceMap, | ||||
|  | ||||
|     Free = static_cast<u32>(Svc::MemoryState::Free), | ||||
|     Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped, | ||||
|     Static = static_cast<u32>(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical, | ||||
|     Code = static_cast<u32>(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess, | ||||
|     CodeData = static_cast<u32>(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess | | ||||
|                FlagCanCodeMemory, | ||||
|     Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted, | ||||
|     Normal = static_cast<u32>(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory, | ||||
|  | ||||
|     AliasCode = static_cast<u32>(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess | | ||||
|                 FlagCanCodeAlias, | ||||
|     AliasCodeData = static_cast<u32>(Svc::MemoryState::AliasCodeData) | FlagsData | | ||||
|                     FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory, | ||||
|  | ||||
|     Ipc = static_cast<u32>(Svc::MemoryState::Ipc) | FlagsMisc | FlagCanAlignedDeviceMap | | ||||
|           FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | ||||
|  | ||||
|     Stack = static_cast<u32>(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap | | ||||
|             FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | ||||
|  | ||||
|     ThreadLocal = | ||||
|         static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, | ||||
|  | ||||
|     Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | | ||||
|                  FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | | ||||
|                  FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | ||||
|  | ||||
|     SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | | ||||
|                        FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | ||||
|  | ||||
|     SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | | ||||
|                  FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | ||||
|  | ||||
|     Inaccessible = static_cast<u32>(Svc::MemoryState::Inaccessible), | ||||
|  | ||||
|     NonSecureIpc = static_cast<u32>(Svc::MemoryState::NonSecureIpc) | FlagsMisc | | ||||
|                    FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | ||||
|  | ||||
|     NonDeviceIpc = | ||||
|         static_cast<u32>(Svc::MemoryState::NonDeviceIpc) | FlagsMisc | FlagCanUseNonDeviceIpc, | ||||
|  | ||||
|     Kernel = static_cast<u32>(Svc::MemoryState::Kernel) | FlagMapped, | ||||
|  | ||||
|     GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped | | ||||
|                     FlagReferenceCounted | FlagCanDebug, | ||||
|     CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted, | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(MemoryState); | ||||
|  | ||||
| static_assert(static_cast<u32>(MemoryState::Free) == 0x00000000); | ||||
| static_assert(static_cast<u32>(MemoryState::Io) == 0x00002001); | ||||
| static_assert(static_cast<u32>(MemoryState::Static) == 0x00042002); | ||||
| static_assert(static_cast<u32>(MemoryState::Code) == 0x00DC7E03); | ||||
| static_assert(static_cast<u32>(MemoryState::CodeData) == 0x03FEBD04); | ||||
| static_assert(static_cast<u32>(MemoryState::Normal) == 0x037EBD05); | ||||
| static_assert(static_cast<u32>(MemoryState::Shared) == 0x00402006); | ||||
| static_assert(static_cast<u32>(MemoryState::AliasCode) == 0x00DD7E08); | ||||
| static_assert(static_cast<u32>(MemoryState::AliasCodeData) == 0x03FFBD09); | ||||
| static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A); | ||||
| static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B); | ||||
| static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C); | ||||
| static_assert(static_cast<u32>(MemoryState::Transfered) == 0x015C3C0D); | ||||
| static_assert(static_cast<u32>(MemoryState::SharedTransfered) == 0x005C380E); | ||||
| static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F); | ||||
| static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010); | ||||
| static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811); | ||||
| static_assert(static_cast<u32>(MemoryState::NonDeviceIpc) == 0x004C2812); | ||||
| static_assert(static_cast<u32>(MemoryState::Kernel) == 0x00002013); | ||||
| static_assert(static_cast<u32>(MemoryState::GeneratedCode) == 0x00402214); | ||||
| static_assert(static_cast<u32>(MemoryState::CodeOut) == 0x00402015); | ||||
|  | ||||
| enum class MemoryPermission : u8 { | ||||
|     None = 0, | ||||
|     Mask = static_cast<u8>(~None), | ||||
|  | ||||
|     Read = 1 << 0, | ||||
|     Write = 1 << 1, | ||||
|     Execute = 1 << 2, | ||||
|  | ||||
|     ReadAndWrite = Read | Write, | ||||
|     ReadAndExecute = Read | Execute, | ||||
|  | ||||
|     UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write | | ||||
|                                Svc::MemoryPermission::Execute), | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission); | ||||
|  | ||||
| enum class MemoryAttribute : u8 { | ||||
|     None = 0x00, | ||||
|     Mask = 0x7F, | ||||
|     All = Mask, | ||||
|     DontCareMask = 0x80, | ||||
|  | ||||
|     Locked = static_cast<u8>(Svc::MemoryAttribute::Locked), | ||||
|     IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked), | ||||
|     DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared), | ||||
|     Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached), | ||||
|  | ||||
|     IpcAndDeviceMapped = IpcLocked | DeviceShared, | ||||
|     LockedAndIpcLocked = Locked | IpcLocked, | ||||
|     DeviceSharedAndUncached = DeviceShared | Uncached | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute); | ||||
|  | ||||
| static_assert((static_cast<u8>(MemoryAttribute::Mask) & | ||||
|                static_cast<u8>(MemoryAttribute::DontCareMask)) == 0); | ||||
|  | ||||
| struct MemoryInfo { | ||||
|     VAddr addr{}; | ||||
|     std::size_t size{}; | ||||
|     MemoryState state{}; | ||||
|     MemoryPermission perm{}; | ||||
|     MemoryAttribute attribute{}; | ||||
|     MemoryPermission original_perm{}; | ||||
|     u16 ipc_lock_count{}; | ||||
|     u16 device_use_count{}; | ||||
|  | ||||
|     constexpr Svc::MemoryInfo GetSvcMemoryInfo() const { | ||||
|         return { | ||||
|             addr, | ||||
|             size, | ||||
|             static_cast<Svc::MemoryState>(state & MemoryState::Mask), | ||||
|             static_cast<Svc::MemoryAttribute>(attribute & MemoryAttribute::Mask), | ||||
|             static_cast<Svc::MemoryPermission>(perm & MemoryPermission::UserMask), | ||||
|             ipc_lock_count, | ||||
|             device_use_count, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     constexpr VAddr GetAddress() const { | ||||
|         return addr; | ||||
|     } | ||||
|     constexpr std::size_t GetSize() const { | ||||
|         return size; | ||||
|     } | ||||
|     constexpr std::size_t GetNumPages() const { | ||||
|         return GetSize() / PageSize; | ||||
|     } | ||||
|     constexpr VAddr GetEndAddress() const { | ||||
|         return GetAddress() + GetSize(); | ||||
|     } | ||||
|     constexpr VAddr GetLastAddress() const { | ||||
|         return GetEndAddress() - 1; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class MemoryBlock final { | ||||
|     friend class MemoryBlockManager; | ||||
|  | ||||
| private: | ||||
|     VAddr addr{}; | ||||
|     std::size_t num_pages{}; | ||||
|     MemoryState state{MemoryState::None}; | ||||
|     u16 ipc_lock_count{}; | ||||
|     u16 device_use_count{}; | ||||
|     MemoryPermission perm{MemoryPermission::None}; | ||||
|     MemoryPermission original_perm{MemoryPermission::None}; | ||||
|     MemoryAttribute attribute{MemoryAttribute::None}; | ||||
|  | ||||
| public: | ||||
|     static constexpr int Compare(const MemoryBlock& lhs, const MemoryBlock& rhs) { | ||||
|         if (lhs.GetAddress() < rhs.GetAddress()) { | ||||
|             return -1; | ||||
|         } else if (lhs.GetAddress() <= rhs.GetLastAddress()) { | ||||
|             return 0; | ||||
|         } else { | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     constexpr MemoryBlock() = default; | ||||
|     constexpr MemoryBlock(VAddr addr, std::size_t num_pages, MemoryState state, | ||||
|                           MemoryPermission perm, MemoryAttribute attribute) | ||||
|         : addr{addr}, num_pages(num_pages), state{state}, perm{perm}, attribute{attribute} {} | ||||
|  | ||||
|     constexpr VAddr GetAddress() const { | ||||
|         return addr; | ||||
|     } | ||||
|  | ||||
|     constexpr std::size_t GetNumPages() const { | ||||
|         return num_pages; | ||||
|     } | ||||
|  | ||||
|     constexpr std::size_t GetSize() const { | ||||
|         return GetNumPages() * PageSize; | ||||
|     } | ||||
|  | ||||
|     constexpr VAddr GetEndAddress() const { | ||||
|         return GetAddress() + GetSize(); | ||||
|     } | ||||
|  | ||||
|     constexpr VAddr GetLastAddress() const { | ||||
|         return GetEndAddress() - 1; | ||||
|     } | ||||
|  | ||||
|     constexpr MemoryInfo GetMemoryInfo() const { | ||||
|         return { | ||||
|             GetAddress(), GetSize(),     state,          perm, | ||||
|             attribute,    original_perm, ipc_lock_count, device_use_count, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     constexpr bool HasProperties(MemoryState s, MemoryPermission p, MemoryAttribute a) const { | ||||
|         constexpr MemoryAttribute AttributeIgnoreMask{MemoryAttribute::DontCareMask | | ||||
|                                                       MemoryAttribute::IpcLocked | | ||||
|                                                       MemoryAttribute::DeviceShared}; | ||||
|         return state == s && perm == p && | ||||
|                (attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask); | ||||
|     } | ||||
|  | ||||
|     constexpr bool HasSameProperties(const MemoryBlock& rhs) const { | ||||
|         return state == rhs.state && perm == rhs.perm && original_perm == rhs.original_perm && | ||||
|                attribute == rhs.attribute && ipc_lock_count == rhs.ipc_lock_count && | ||||
|                device_use_count == rhs.device_use_count; | ||||
|     } | ||||
|  | ||||
|     constexpr bool Contains(VAddr start) const { | ||||
|         return GetAddress() <= start && start <= GetEndAddress(); | ||||
|     } | ||||
|  | ||||
|     constexpr void Add(std::size_t count) { | ||||
|         ASSERT(count > 0); | ||||
|         ASSERT(GetAddress() + count * PageSize - 1 < GetEndAddress() + count * PageSize - 1); | ||||
|  | ||||
|         num_pages += count; | ||||
|     } | ||||
|  | ||||
|     constexpr void Update(MemoryState new_state, MemoryPermission new_perm, | ||||
|                           MemoryAttribute new_attribute) { | ||||
|         ASSERT(original_perm == MemoryPermission::None); | ||||
|         ASSERT((attribute & MemoryAttribute::IpcLocked) == MemoryAttribute::None); | ||||
|  | ||||
|         state = new_state; | ||||
|         perm = new_perm; | ||||
|  | ||||
|         // TODO(bunnei): Is this right? | ||||
|         attribute = static_cast<MemoryAttribute>( | ||||
|             new_attribute /*| (attribute & (MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared))*/); | ||||
|     } | ||||
|  | ||||
|     constexpr MemoryBlock Split(VAddr split_addr) { | ||||
|         ASSERT(GetAddress() < split_addr); | ||||
|         ASSERT(Contains(split_addr)); | ||||
|         ASSERT(Common::IsAligned(split_addr, PageSize)); | ||||
|  | ||||
|         MemoryBlock block; | ||||
|         block.addr = addr; | ||||
|         block.num_pages = (split_addr - GetAddress()) / PageSize; | ||||
|         block.state = state; | ||||
|         block.ipc_lock_count = ipc_lock_count; | ||||
|         block.device_use_count = device_use_count; | ||||
|         block.perm = perm; | ||||
|         block.original_perm = original_perm; | ||||
|         block.attribute = attribute; | ||||
|  | ||||
|         addr = split_addr; | ||||
|         num_pages -= block.num_pages; | ||||
|  | ||||
|         return block; | ||||
|     } | ||||
| }; | ||||
| static_assert(std::is_trivially_destructible<MemoryBlock>::value); | ||||
|  | ||||
| } // namespace Kernel::Memory | ||||
		Reference in New Issue
	
	Block a user