diff options
Diffstat (limited to 'src/core/hle/kernel/memory')
| -rw-r--r-- | src/core/hle/kernel/memory/address_space_info.cpp | 119 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/address_space_info.h | 34 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_block.h | 335 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_block_manager.cpp | 223 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_block_manager.h | 66 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_layout.h | 90 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_manager.cpp | 175 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_manager.h | 96 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/memory_types.h | 18 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_heap.cpp | 119 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_heap.h | 370 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_linked_list.h | 92 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_table.cpp | 1184 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_table.h | 277 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/slab_heap.h | 163 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/system_control.cpp | 40 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/system_control.h | 13 |
17 files changed, 0 insertions, 3414 deletions
diff --git a/src/core/hle/kernel/memory/address_space_info.cpp b/src/core/hle/kernel/memory/address_space_info.cpp deleted file mode 100644 index 6cf43ba24..000000000 --- a/src/core/hle/kernel/memory/address_space_info.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#include <array> - -#include "common/assert.h" -#include "core/hle/kernel/memory/address_space_info.h" - -namespace Kernel::Memory { - -namespace { - -enum : u64 { - Size_1_MB = 0x100000, - Size_2_MB = 2 * Size_1_MB, - Size_128_MB = 128 * Size_1_MB, - Size_1_GB = 0x40000000, - Size_2_GB = 2 * Size_1_GB, - Size_4_GB = 4 * Size_1_GB, - Size_6_GB = 6 * Size_1_GB, - Size_64_GB = 64 * Size_1_GB, - Size_512_GB = 512 * Size_1_GB, - Invalid = std::numeric_limits<u64>::max(), -}; - -// clang-format off -constexpr std::array<AddressSpaceInfo, 13> AddressSpaceInfos{{ - { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = AddressSpaceInfo::Type::Is32Bit, }, - { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, - { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Heap, }, - { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Alias, }, - { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Is32Bit, }, - { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, - { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, - { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Alias, }, - { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Large64Bit, }, - { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Is32Bit }, - { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, - { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Alias, }, - { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = AddressSpaceInfo::Type::Stack, }, -}}; -// clang-format on - -constexpr bool IsAllowedIndexForAddress(std::size_t index) { - return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid; -} - -using IndexArray = std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)>; - -constexpr IndexArray AddressSpaceIndices32Bit{ - 0, 1, 0, 2, 0, 3, -}; - -constexpr IndexArray AddressSpaceIndices36Bit{ - 4, 5, 4, 6, 4, 7, -}; - -constexpr IndexArray AddressSpaceIndices39Bit{ - 9, 8, 8, 10, 12, 11, -}; - -constexpr bool IsAllowed32BitType(AddressSpaceInfo::Type type) { - return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit && - type != AddressSpaceInfo::Type::Stack; -} - -constexpr bool IsAllowed36BitType(AddressSpaceInfo::Type type) { - return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit && - type != AddressSpaceInfo::Type::Stack; -} - -constexpr bool IsAllowed39BitType(AddressSpaceInfo::Type type) { - return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Small64Bit; -} - -} // namespace - -u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { - const std::size_t index{static_cast<std::size_t>(type)}; - switch (width) { - case 32: - ASSERT(IsAllowed32BitType(type)); - ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address; - case 36: - ASSERT(IsAllowed36BitType(type)); - ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address; - case 39: - ASSERT(IsAllowed39BitType(type)); - ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; - } - UNREACHABLE(); - return 0; -} - -std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { - const std::size_t index{static_cast<std::size_t>(type)}; - switch (width) { - case 32: - ASSERT(IsAllowed32BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size; - case 36: - ASSERT(IsAllowed36BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size; - case 39: - ASSERT(IsAllowed39BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; - } - UNREACHABLE(); - return 0; -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/address_space_info.h b/src/core/hle/kernel/memory/address_space_info.h deleted file mode 100644 index a4e6e91e5..000000000 --- a/src/core/hle/kernel/memory/address_space_info.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#pragma once - -#include "common/common_types.h" - -namespace Kernel::Memory { - -struct AddressSpaceInfo final { - enum class Type : u32 { - Is32Bit = 0, - Small64Bit = 1, - Large64Bit = 2, - Heap = 3, - Stack = 4, - Alias = 5, - Count, - }; - - static u64 GetAddressSpaceStart(std::size_t width, Type type); - static std::size_t GetAddressSpaceSize(std::size_t width, Type type); - - const std::size_t bit_width{}; - const std::size_t address{}; - const std::size_t size{}; - const Type type{}; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_block.h b/src/core/hle/kernel/memory/memory_block.h deleted file mode 100644 index 83acece1e..000000000 --- a/src/core/hle/kernel/memory/memory_block.h +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#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 = 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, - - Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | - FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - - SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | 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::Transferred) == 0x015C3C0D); -static_assert(static_cast<u32>(MemoryState::SharedTransferred) == 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, - }; - } - - void ShareToDevice(MemoryPermission /*new_perm*/) { - ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared || - device_use_count == 0); - attribute |= MemoryAttribute::DeviceShared; - const u16 new_use_count{++device_use_count}; - ASSERT(new_use_count > 0); - } - - void UnshareToDevice(MemoryPermission /*new_perm*/) { - ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared); - const u16 prev_use_count{device_use_count--}; - ASSERT(prev_use_count > 0); - if (prev_use_count == 1) { - attribute &= ~MemoryAttribute::DeviceShared; - } - } - -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; - - 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 diff --git a/src/core/hle/kernel/memory/memory_block_manager.cpp b/src/core/hle/kernel/memory/memory_block_manager.cpp deleted file mode 100644 index 0732fa5a1..000000000 --- a/src/core/hle/kernel/memory/memory_block_manager.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/memory/memory_block_manager.h" -#include "core/hle/kernel/memory/memory_types.h" - -namespace Kernel::Memory { - -MemoryBlockManager::MemoryBlockManager(VAddr start_addr, VAddr end_addr) - : start_addr{start_addr}, end_addr{end_addr} { - const u64 num_pages{(end_addr - start_addr) / PageSize}; - memory_block_tree.emplace_back(start_addr, num_pages, MemoryState::Free, MemoryPermission::None, - MemoryAttribute::None); -} - -MemoryBlockManager::iterator MemoryBlockManager::FindIterator(VAddr addr) { - auto node{memory_block_tree.begin()}; - while (node != end()) { - const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()}; - if (node->GetAddress() <= addr && end_addr - 1 >= addr) { - return node; - } - node = std::next(node); - } - return end(); -} - -VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_num_pages, - std::size_t num_pages, std::size_t align, std::size_t offset, - std::size_t guard_pages) { - if (num_pages == 0) { - return {}; - } - - const VAddr region_end{region_start + region_num_pages * PageSize}; - const VAddr region_last{region_end - 1}; - for (auto it{FindIterator(region_start)}; it != memory_block_tree.cend(); it++) { - const auto info{it->GetMemoryInfo()}; - if (region_last < info.GetAddress()) { - break; - } - - if (info.state != MemoryState::Free) { - continue; - } - - VAddr area{(info.GetAddress() <= region_start) ? region_start : info.GetAddress()}; - area += guard_pages * PageSize; - - const VAddr offset_area{Common::AlignDown(area, align) + offset}; - area = (area <= offset_area) ? offset_area : offset_area + align; - - const VAddr area_end{area + num_pages * PageSize + guard_pages * PageSize}; - const VAddr area_last{area_end - 1}; - - if (info.GetAddress() <= area && area < area_last && area_last <= region_last && - area_last <= info.GetLastAddress()) { - return area; - } - } - - return {}; -} - -void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState prev_state, - MemoryPermission prev_perm, MemoryAttribute prev_attribute, - MemoryState state, MemoryPermission perm, - MemoryAttribute attribute) { - const VAddr end_addr{addr + num_pages * PageSize}; - iterator node{memory_block_tree.begin()}; - - prev_attribute |= MemoryAttribute::IpcAndDeviceMapped; - - while (node != memory_block_tree.end()) { - MemoryBlock* block{&(*node)}; - iterator next_node{std::next(node)}; - const VAddr cur_addr{block->GetAddress()}; - const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - - if (addr < cur_end_addr && cur_addr < end_addr) { - if (!block->HasProperties(prev_state, prev_perm, prev_attribute)) { - node = next_node; - continue; - } - - iterator new_node{node}; - if (addr > cur_addr) { - memory_block_tree.insert(node, block->Split(addr)); - } - - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); - } - - new_node->Update(state, perm, attribute); - - MergeAdjacent(new_node, next_node); - } - - if (cur_end_addr - 1 >= end_addr - 1) { - break; - } - - node = next_node; - } -} - -void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState state, - MemoryPermission perm, MemoryAttribute attribute) { - const VAddr end_addr{addr + num_pages * PageSize}; - iterator node{memory_block_tree.begin()}; - - while (node != memory_block_tree.end()) { - MemoryBlock* block{&(*node)}; - iterator next_node{std::next(node)}; - const VAddr cur_addr{block->GetAddress()}; - const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - - if (addr < cur_end_addr && cur_addr < end_addr) { - iterator new_node{node}; - - if (addr > cur_addr) { - memory_block_tree.insert(node, block->Split(addr)); - } - - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); - } - - new_node->Update(state, perm, attribute); - - MergeAdjacent(new_node, next_node); - } - - if (cur_end_addr - 1 >= end_addr - 1) { - break; - } - - node = next_node; - } -} - -void MemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, - MemoryPermission perm) { - const VAddr end_addr{addr + num_pages * PageSize}; - iterator node{memory_block_tree.begin()}; - - while (node != memory_block_tree.end()) { - MemoryBlock* block{&(*node)}; - iterator next_node{std::next(node)}; - const VAddr cur_addr{block->GetAddress()}; - const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - - if (addr < cur_end_addr && cur_addr < end_addr) { - iterator new_node{node}; - - if (addr > cur_addr) { - memory_block_tree.insert(node, block->Split(addr)); - } - - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); - } - - lock_func(new_node, perm); - - MergeAdjacent(new_node, next_node); - } - - if (cur_end_addr - 1 >= end_addr - 1) { - break; - } - - node = next_node; - } -} - -void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) { - const_iterator it{FindIterator(start)}; - MemoryInfo info{}; - do { - info = it->GetMemoryInfo(); - func(info); - it = std::next(it); - } while (info.addr + info.size - 1 < end - 1 && it != cend()); -} - -void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) { - MemoryBlock* block{&(*it)}; - - auto EraseIt = [&](const iterator it_to_erase) { - if (next_it == it_to_erase) { - next_it = std::next(next_it); - } - memory_block_tree.erase(it_to_erase); - }; - - if (it != memory_block_tree.begin()) { - MemoryBlock* prev{&(*std::prev(it))}; - - if (block->HasSameProperties(*prev)) { - const iterator prev_it{std::prev(it)}; - - prev->Add(block->GetNumPages()); - EraseIt(it); - - it = prev_it; - block = prev; - } - } - - if (it != cend()) { - const MemoryBlock* const next{&(*std::next(it))}; - - if (block->HasSameProperties(*next)) { - block->Add(next->GetNumPages()); - EraseIt(std::next(it)); - } - } -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_block_manager.h b/src/core/hle/kernel/memory/memory_block_manager.h deleted file mode 100644 index f57d1bbcc..000000000 --- a/src/core/hle/kernel/memory/memory_block_manager.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <functional> -#include <list> - -#include "common/common_types.h" -#include "core/hle/kernel/memory/memory_block.h" - -namespace Kernel::Memory { - -class MemoryBlockManager final { -public: - using MemoryBlockTree = std::list<MemoryBlock>; - using iterator = MemoryBlockTree::iterator; - using const_iterator = MemoryBlockTree::const_iterator; - -public: - MemoryBlockManager(VAddr start_addr, VAddr end_addr); - - iterator end() { - return memory_block_tree.end(); - } - const_iterator end() const { - return memory_block_tree.end(); - } - const_iterator cend() const { - return memory_block_tree.cend(); - } - - iterator FindIterator(VAddr addr); - - VAddr FindFreeArea(VAddr region_start, std::size_t region_num_pages, std::size_t num_pages, - std::size_t align, std::size_t offset, std::size_t guard_pages); - - void Update(VAddr addr, std::size_t num_pages, MemoryState prev_state, - MemoryPermission prev_perm, MemoryAttribute prev_attribute, MemoryState state, - MemoryPermission perm, MemoryAttribute attribute); - - void Update(VAddr addr, std::size_t num_pages, MemoryState state, - MemoryPermission perm = MemoryPermission::None, - MemoryAttribute attribute = MemoryAttribute::None); - - using LockFunc = std::function<void(iterator, MemoryPermission)>; - void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, MemoryPermission perm); - - using IterateFunc = std::function<void(const MemoryInfo&)>; - void IterateForRange(VAddr start, VAddr end, IterateFunc&& func); - - MemoryBlock& FindBlock(VAddr addr) { - return *FindIterator(addr); - } - -private: - void MergeAdjacent(iterator it, iterator& next_it); - - [[maybe_unused]] const VAddr start_addr; - [[maybe_unused]] const VAddr end_addr; - - MemoryBlockTree memory_block_tree; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_layout.h b/src/core/hle/kernel/memory/memory_layout.h deleted file mode 100644 index c7c0b2f49..000000000 --- a/src/core/hle/kernel/memory/memory_layout.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" -#include "core/device_memory.h" - -namespace Kernel::Memory { - -constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024; -constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39; -constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48; -constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth; -constexpr std::size_t KernelVirtualAddressSpaceEnd = - KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment); -constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1; -constexpr std::size_t KernelVirtualAddressSpaceSize = - KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase; - -constexpr bool IsKernelAddressKey(VAddr key) { - return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast; -} - -constexpr bool IsKernelAddress(VAddr address) { - return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; -} - -class MemoryRegion final { - friend class MemoryLayout; - -public: - constexpr PAddr StartAddress() const { - return start_address; - } - - constexpr PAddr EndAddress() const { - return end_address; - } - -private: - constexpr MemoryRegion() = default; - constexpr MemoryRegion(PAddr start_address, PAddr end_address) - : start_address{start_address}, end_address{end_address} {} - - const PAddr start_address{}; - const PAddr end_address{}; -}; - -class MemoryLayout final { -public: - constexpr const MemoryRegion& Application() const { - return application; - } - - constexpr const MemoryRegion& Applet() const { - return applet; - } - - constexpr const MemoryRegion& System() const { - return system; - } - - static constexpr MemoryLayout GetDefaultLayout() { - constexpr std::size_t application_size{0xcd500000}; - constexpr std::size_t applet_size{0x1fb00000}; - constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size}; - constexpr PAddr application_end_address{Core::DramMemoryMap::End}; - constexpr PAddr applet_start_address{application_start_address - applet_size}; - constexpr PAddr applet_end_address{applet_start_address + applet_size}; - constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd}; - constexpr PAddr system_end_address{applet_start_address}; - return {application_start_address, application_end_address, applet_start_address, - applet_end_address, system_start_address, system_end_address}; - } - -private: - constexpr MemoryLayout(PAddr application_start_address, std::size_t application_size, - PAddr applet_start_address, std::size_t applet_size, - PAddr system_start_address, std::size_t system_size) - : application{application_start_address, application_size}, - applet{applet_start_address, applet_size}, system{system_start_address, system_size} {} - - const MemoryRegion application; - const MemoryRegion applet; - const MemoryRegion system; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/memory/memory_manager.cpp deleted file mode 100644 index 77f135cdc..000000000 --- a/src/core/hle/kernel/memory/memory_manager.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_types.h" -#include "common/scope_exit.h" -#include "core/hle/kernel/memory/memory_manager.h" -#include "core/hle/kernel/memory/page_linked_list.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel::Memory { - -std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) { - const auto size{end_address - start_address}; - - // Calculate metadata sizes - const auto ref_count_size{(size / PageSize) * sizeof(u16)}; - const auto optimize_map_size{(Common::AlignUp((size / PageSize), 64) / 64) * sizeof(u64)}; - const auto manager_size{Common::AlignUp(optimize_map_size + ref_count_size, PageSize)}; - const auto page_heap_size{PageHeap::CalculateMetadataOverheadSize(size)}; - const auto total_metadata_size{manager_size + page_heap_size}; - ASSERT(manager_size <= total_metadata_size); - ASSERT(Common::IsAligned(total_metadata_size, PageSize)); - - // Setup region - pool = new_pool; - - // Initialize the manager's KPageHeap - heap.Initialize(start_address, size, page_heap_size); - - // Free the memory to the heap - heap.Free(start_address, size / PageSize); - - // Update the heap's used size - heap.UpdateUsedSize(); - - return total_metadata_size; -} - -void MemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) { - ASSERT(pool < Pool::Count); - managers[static_cast<std::size_t>(pool)].Initialize(pool, start_address, end_address); -} - -VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align_pages, Pool pool, - Direction dir) { - // Early return if we're allocating no pages - if (num_pages == 0) { - return {}; - } - - // Lock the pool that we're allocating from - const auto pool_index{static_cast<std::size_t>(pool)}; - std::lock_guard lock{pool_locks[pool_index]}; - - // Choose a heap based on our page size request - const s32 heap_index{PageHeap::GetAlignedBlockIndex(num_pages, align_pages)}; - - // Loop, trying to iterate from each block - // TODO (bunnei): Support multiple managers - Impl& chosen_manager{managers[pool_index]}; - VAddr allocated_block{chosen_manager.AllocateBlock(heap_index)}; - - // If we failed to allocate, quit now - if (!allocated_block) { - return {}; - } - - // If we allocated more than we need, free some - const auto allocated_pages{PageHeap::GetBlockNumPages(heap_index)}; - if (allocated_pages > num_pages) { - chosen_manager.Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages); - } - - return allocated_block; -} - -ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir) { - ASSERT(page_list.GetNumPages() == 0); - - // Early return if we're allocating no pages - if (num_pages == 0) { - return RESULT_SUCCESS; - } - - // Lock the pool that we're allocating from - const auto pool_index{static_cast<std::size_t>(pool)}; - std::lock_guard lock{pool_locks[pool_index]}; - - // Choose a heap based on our page size request - const s32 heap_index{PageHeap::GetBlockIndex(num_pages)}; - if (heap_index < 0) { - return ResultOutOfMemory; - } - - // TODO (bunnei): Support multiple managers - Impl& chosen_manager{managers[pool_index]}; - - // Ensure that we don't leave anything un-freed - auto group_guard = detail::ScopeExit([&] { - for (const auto& it : page_list.Nodes()) { - const auto min_num_pages{std::min<size_t>( - it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)}; - chosen_manager.Free(it.GetAddress(), min_num_pages); - } - }); - - // Keep allocating until we've allocated all our pages - for (s32 index{heap_index}; index >= 0 && num_pages > 0; index--) { - const auto pages_per_alloc{PageHeap::GetBlockNumPages(index)}; - - while (num_pages >= pages_per_alloc) { - // Allocate a block - VAddr allocated_block{chosen_manager.AllocateBlock(index)}; - if (!allocated_block) { - break; - } - - // Safely add it to our group - { - auto block_guard = detail::ScopeExit( - [&] { chosen_manager.Free(allocated_block, pages_per_alloc); }); - - if (const ResultCode result{page_list.AddBlock(allocated_block, pages_per_alloc)}; - result.IsError()) { - return result; - } - - block_guard.Cancel(); - } - - num_pages -= pages_per_alloc; - } - } - - // Only succeed if we allocated as many pages as we wanted - if (num_pages) { - return ResultOutOfMemory; - } - - // We succeeded! - group_guard.Cancel(); - return RESULT_SUCCESS; -} - -ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir) { - // Early return if we're freeing no pages - if (!num_pages) { - return RESULT_SUCCESS; - } - - // Lock the pool that we're freeing from - const auto pool_index{static_cast<std::size_t>(pool)}; - std::lock_guard lock{pool_locks[pool_index]}; - - // TODO (bunnei): Support multiple managers - Impl& chosen_manager{managers[pool_index]}; - - // Free all of the pages - for (const auto& it : page_list.Nodes()) { - const auto min_num_pages{std::min<size_t>( - it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)}; - chosen_manager.Free(it.GetAddress(), min_num_pages); - } - - return RESULT_SUCCESS; -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_manager.h b/src/core/hle/kernel/memory/memory_manager.h deleted file mode 100644 index 3cf444857..000000000 --- a/src/core/hle/kernel/memory/memory_manager.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <mutex> - -#include "common/common_types.h" -#include "core/hle/kernel/memory/page_heap.h" -#include "core/hle/result.h" - -namespace Kernel::Memory { - -class PageLinkedList; - -class MemoryManager final : NonCopyable { -public: - enum class Pool : u32 { - Application = 0, - Applet = 1, - System = 2, - SystemNonSecure = 3, - - Count, - - Shift = 4, - Mask = (0xF << Shift), - }; - - enum class Direction : u32 { - FromFront = 0, - FromBack = 1, - - Shift = 0, - Mask = (0xF << Shift), - }; - - MemoryManager() = default; - - constexpr std::size_t GetSize(Pool pool) const { - return managers[static_cast<std::size_t>(pool)].GetSize(); - } - - void InitializeManager(Pool pool, u64 start_address, u64 end_address); - VAddr AllocateContinuous(std::size_t num_pages, std::size_t align_pages, Pool pool, - Direction dir = Direction::FromFront); - ResultCode Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir = Direction::FromFront); - ResultCode Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir = Direction::FromFront); - - static constexpr std::size_t MaxManagerCount = 10; - -private: - class Impl final : NonCopyable { - private: - using RefCount = u16; - - private: - PageHeap heap; - Pool pool{}; - - public: - Impl() = default; - - std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address); - - VAddr AllocateBlock(s32 index) { - return heap.AllocateBlock(index); - } - - void Free(VAddr addr, std::size_t num_pages) { - heap.Free(addr, num_pages); - } - - constexpr std::size_t GetSize() const { - return heap.GetSize(); - } - - constexpr VAddr GetAddress() const { - return heap.GetAddress(); - } - - constexpr VAddr GetEndAddress() const { - return heap.GetEndAddress(); - } - }; - -private: - std::array<std::mutex, static_cast<std::size_t>(Pool::Count)> pool_locks; - std::array<Impl, MaxManagerCount> managers; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_types.h b/src/core/hle/kernel/memory/memory_types.h deleted file mode 100644 index a75bf77c0..000000000 --- a/src/core/hle/kernel/memory/memory_types.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> - -#include "common/common_types.h" - -namespace Kernel::Memory { - -constexpr std::size_t PageBits{12}; -constexpr std::size_t PageSize{1 << PageBits}; - -using Page = std::array<u8, PageSize>; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_heap.cpp b/src/core/hle/kernel/memory/page_heap.cpp deleted file mode 100644 index 0ab1f7205..000000000 --- a/src/core/hle/kernel/memory/page_heap.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#include "core/core.h" -#include "core/hle/kernel/memory/page_heap.h" -#include "core/memory.h" - -namespace Kernel::Memory { - -void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) { - // Check our assumptions - ASSERT(Common::IsAligned((address), PageSize)); - ASSERT(Common::IsAligned(size, PageSize)); - - // Set our members - heap_address = address; - heap_size = size; - - // Setup bitmaps - metadata.resize(metadata_size / sizeof(u64)); - u64* cur_bitmap_storage{metadata.data()}; - for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { - const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; - const std::size_t next_block_shift{ - (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; - cur_bitmap_storage = blocks[i].Initialize(heap_address, heap_size, cur_block_shift, - next_block_shift, cur_bitmap_storage); - } -} - -VAddr PageHeap::AllocateBlock(s32 index) { - const std::size_t needed_size{blocks[index].GetSize()}; - - for (s32 i{index}; i < static_cast<s32>(MemoryBlockPageShifts.size()); i++) { - if (const VAddr addr{blocks[i].PopBlock()}; addr) { - if (const std::size_t allocated_size{blocks[i].GetSize()}; - allocated_size > needed_size) { - Free(addr + needed_size, (allocated_size - needed_size) / PageSize); - } - return addr; - } - } - - return 0; -} - -void PageHeap::FreeBlock(VAddr block, s32 index) { - do { - block = blocks[index++].PushBlock(block); - } while (block != 0); -} - -void PageHeap::Free(VAddr addr, std::size_t num_pages) { - // Freeing no pages is a no-op - if (num_pages == 0) { - return; - } - - // Find the largest block size that we can free, and free as many as possible - s32 big_index{static_cast<s32>(MemoryBlockPageShifts.size()) - 1}; - const VAddr start{addr}; - const VAddr end{(num_pages * PageSize) + addr}; - VAddr before_start{start}; - VAddr before_end{start}; - VAddr after_start{end}; - VAddr after_end{end}; - while (big_index >= 0) { - const std::size_t block_size{blocks[big_index].GetSize()}; - const VAddr big_start{Common::AlignUp((start), block_size)}; - const VAddr big_end{Common::AlignDown((end), block_size)}; - if (big_start < big_end) { - // Free as many big blocks as we can - for (auto block{big_start}; block < big_end; block += block_size) { - FreeBlock(block, big_index); - } - before_end = big_start; - after_start = big_end; - break; - } - big_index--; - } - ASSERT(big_index >= 0); - - // Free space before the big blocks - for (s32 i{big_index - 1}; i >= 0; i--) { - const std::size_t block_size{blocks[i].GetSize()}; - while (before_start + block_size <= before_end) { - before_end -= block_size; - FreeBlock(before_end, i); - } - } - - // Free space after the big blocks - for (s32 i{big_index - 1}; i >= 0; i--) { - const std::size_t block_size{blocks[i].GetSize()}; - while (after_start + block_size <= after_end) { - FreeBlock(after_start, i); - after_start += block_size; - } - } -} - -std::size_t PageHeap::CalculateMetadataOverheadSize(std::size_t region_size) { - std::size_t overhead_size = 0; - for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { - const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; - const std::size_t next_block_shift{ - (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; - overhead_size += PageHeap::Block::CalculateMetadataOverheadSize( - region_size, cur_block_shift, next_block_shift); - } - return Common::AlignUp(overhead_size, PageSize); -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_heap.h b/src/core/hle/kernel/memory/page_heap.h deleted file mode 100644 index 131093284..000000000 --- a/src/core/hle/kernel/memory/page_heap.h +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#pragma once - -#include <array> -#include <bit> -#include <vector> - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hle/kernel/memory/memory_types.h" - -namespace Kernel::Memory { - -class PageHeap final : NonCopyable { -public: - static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) { - const auto target_pages{std::max(num_pages, align_pages)}; - for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) { - if (target_pages <= - (static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) { - return static_cast<s32>(i); - } - } - return -1; - } - - static constexpr s32 GetBlockIndex(std::size_t num_pages) { - for (s32 i{static_cast<s32>(NumMemoryBlockPageShifts) - 1}; i >= 0; i--) { - if (num_pages >= (static_cast<std::size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) { - return i; - } - } - return -1; - } - - static constexpr std::size_t GetBlockSize(std::size_t index) { - return static_cast<std::size_t>(1) << MemoryBlockPageShifts[index]; - } - - static constexpr std::size_t GetBlockNumPages(std::size_t index) { - return GetBlockSize(index) / PageSize; - } - -private: - static constexpr std::size_t NumMemoryBlockPageShifts{7}; - static constexpr std::array<std::size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{ - 0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E, - }; - - class Block final : NonCopyable { - private: - class Bitmap final : NonCopyable { - public: - static constexpr std::size_t MaxDepth{4}; - - private: - std::array<u64*, MaxDepth> bit_storages{}; - std::size_t num_bits{}; - std::size_t used_depths{}; - - public: - constexpr Bitmap() = default; - - constexpr std::size_t GetNumBits() const { - return num_bits; - } - constexpr s32 GetHighestDepthIndex() const { - return static_cast<s32>(used_depths) - 1; - } - - constexpr u64* Initialize(u64* storage, std::size_t size) { - //* Initially, everything is un-set - num_bits = 0; - - // Calculate the needed bitmap depth - used_depths = static_cast<std::size_t>(GetRequiredDepth(size)); - ASSERT(used_depths <= MaxDepth); - - // Set the bitmap pointers - for (s32 depth{GetHighestDepthIndex()}; depth >= 0; depth--) { - bit_storages[depth] = storage; - size = Common::AlignUp(size, 64) / 64; - storage += size; - } - - return storage; - } - - s64 FindFreeBlock() const { - uintptr_t offset{}; - s32 depth{}; - - do { - const u64 v{bit_storages[depth][offset]}; - if (v == 0) { - // Non-zero depth indicates that a previous level had a free block - ASSERT(depth == 0); - return -1; - } - offset = offset * 64 + static_cast<u32>(std::countr_zero(v)); - ++depth; - } while (depth < static_cast<s32>(used_depths)); - - return static_cast<s64>(offset); - } - - constexpr void SetBit(std::size_t offset) { - SetBit(GetHighestDepthIndex(), offset); - num_bits++; - } - - constexpr void ClearBit(std::size_t offset) { - ClearBit(GetHighestDepthIndex(), offset); - num_bits--; - } - - constexpr bool ClearRange(std::size_t offset, std::size_t count) { - const s32 depth{GetHighestDepthIndex()}; - const auto bit_ind{offset / 64}; - u64* bits{bit_storages[depth]}; - if (count < 64) { - const auto shift{offset % 64}; - ASSERT(shift + count <= 64); - // Check that all the bits are set - const u64 mask{((1ULL << count) - 1) << shift}; - u64 v{bits[bit_ind]}; - if ((v & mask) != mask) { - return false; - } - - // Clear the bits - v &= ~mask; - bits[bit_ind] = v; - if (v == 0) { - ClearBit(depth - 1, bit_ind); - } - } else { - ASSERT(offset % 64 == 0); - ASSERT(count % 64 == 0); - // Check that all the bits are set - std::size_t remaining{count}; - std::size_t i = 0; - do { - if (bits[bit_ind + i++] != ~u64(0)) { - return false; - } - remaining -= 64; - } while (remaining > 0); - - // Clear the bits - remaining = count; - i = 0; - do { - bits[bit_ind + i] = 0; - ClearBit(depth - 1, bit_ind + i); - i++; - remaining -= 64; - } while (remaining > 0); - } - - num_bits -= count; - return true; - } - - private: - constexpr void SetBit(s32 depth, std::size_t offset) { - while (depth >= 0) { - const auto ind{offset / 64}; - const auto which{offset % 64}; - const u64 mask{1ULL << which}; - - u64* bit{std::addressof(bit_storages[depth][ind])}; - const u64 v{*bit}; - ASSERT((v & mask) == 0); - *bit = v | mask; - if (v) { - break; - } - offset = ind; - depth--; - } - } - - constexpr void ClearBit(s32 depth, std::size_t offset) { - while (depth >= 0) { - const auto ind{offset / 64}; - const auto which{offset % 64}; - const u64 mask{1ULL << which}; - - u64* bit{std::addressof(bit_storages[depth][ind])}; - u64 v{*bit}; - ASSERT((v & mask) != 0); - v &= ~mask; - *bit = v; - if (v) { - break; - } - offset = ind; - depth--; - } - } - - private: - static constexpr s32 GetRequiredDepth(std::size_t region_size) { - s32 depth = 0; - while (true) { - region_size /= 64; - depth++; - if (region_size == 0) { - return depth; - } - } - } - - public: - static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size) { - std::size_t overhead_bits = 0; - for (s32 depth{GetRequiredDepth(region_size) - 1}; depth >= 0; depth--) { - region_size = Common::AlignUp(region_size, 64) / 64; - overhead_bits += region_size; - } - return overhead_bits * sizeof(u64); - } - }; - - private: - Bitmap bitmap; - VAddr heap_address{}; - uintptr_t end_offset{}; - std::size_t block_shift{}; - std::size_t next_block_shift{}; - - public: - constexpr Block() = default; - - constexpr std::size_t GetShift() const { - return block_shift; - } - constexpr std::size_t GetNextShift() const { - return next_block_shift; - } - constexpr std::size_t GetSize() const { - return static_cast<std::size_t>(1) << GetShift(); - } - constexpr std::size_t GetNumPages() const { - return GetSize() / PageSize; - } - constexpr std::size_t GetNumFreeBlocks() const { - return bitmap.GetNumBits(); - } - constexpr std::size_t GetNumFreePages() const { - return GetNumFreeBlocks() * GetNumPages(); - } - - constexpr u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs, - u64* bit_storage) { - // Set shifts - block_shift = bs; - next_block_shift = nbs; - - // Align up the address - VAddr end{addr + size}; - const auto align{(next_block_shift != 0) ? (1ULL << next_block_shift) - : (1ULL << block_shift)}; - addr = Common::AlignDown((addr), align); - end = Common::AlignUp((end), align); - - heap_address = addr; - end_offset = (end - addr) / (1ULL << block_shift); - return bitmap.Initialize(bit_storage, end_offset); - } - - constexpr VAddr PushBlock(VAddr address) { - // Set the bit for the free block - std::size_t offset{(address - heap_address) >> GetShift()}; - bitmap.SetBit(offset); - - // If we have a next shift, try to clear the blocks below and return the address - if (GetNextShift()) { - const auto diff{1ULL << (GetNextShift() - GetShift())}; - offset = Common::AlignDown(offset, diff); - if (bitmap.ClearRange(offset, diff)) { - return heap_address + (offset << GetShift()); - } - } - - // We couldn't coalesce, or we're already as big as possible - return 0; - } - - VAddr PopBlock() { - // Find a free block - const s64 soffset{bitmap.FindFreeBlock()}; - if (soffset < 0) { - return 0; - } - const auto offset{static_cast<std::size_t>(soffset)}; - - // Update our tracking and return it - bitmap.ClearBit(offset); - return heap_address + (offset << GetShift()); - } - - public: - static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size, - std::size_t cur_block_shift, - std::size_t next_block_shift) { - const auto cur_block_size{(1ULL << cur_block_shift)}; - const auto next_block_size{(1ULL << next_block_shift)}; - const auto align{(next_block_shift != 0) ? next_block_size : cur_block_size}; - return Bitmap::CalculateMetadataOverheadSize( - (align * 2 + Common::AlignUp(region_size, align)) / cur_block_size); - } - }; - -public: - PageHeap() = default; - - constexpr VAddr GetAddress() const { - return heap_address; - } - constexpr std::size_t GetSize() const { - return heap_size; - } - constexpr VAddr GetEndAddress() const { - return GetAddress() + GetSize(); - } - constexpr std::size_t GetPageOffset(VAddr block) const { - return (block - GetAddress()) / PageSize; - } - - void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size); - VAddr AllocateBlock(s32 index); - void Free(VAddr addr, std::size_t num_pages); - - void UpdateUsedSize() { - used_size = heap_size - (GetNumFreePages() * PageSize); - } - - static std::size_t CalculateMetadataOverheadSize(std::size_t region_size); - -private: - constexpr std::size_t GetNumFreePages() const { - std::size_t num_free{}; - - for (const auto& block : blocks) { - num_free += block.GetNumFreePages(); - } - - return num_free; - } - - void FreeBlock(VAddr block, s32 index); - - VAddr heap_address{}; - std::size_t heap_size{}; - std::size_t used_size{}; - std::array<Block, NumMemoryBlockPageShifts> blocks{}; - std::vector<u64> metadata; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_linked_list.h b/src/core/hle/kernel/memory/page_linked_list.h deleted file mode 100644 index 45dc13eaf..000000000 --- a/src/core/hle/kernel/memory/page_linked_list.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <list> - -#include "common/assert.h" -#include "common/common_types.h" -#include "core/hle/kernel/memory/memory_types.h" -#include "core/hle/result.h" - -namespace Kernel::Memory { - -class PageLinkedList final { -public: - class Node final { - public: - constexpr Node(u64 addr, std::size_t num_pages) : addr{addr}, num_pages{num_pages} {} - - constexpr u64 GetAddress() const { - return addr; - } - - constexpr std::size_t GetNumPages() const { - return num_pages; - } - - private: - u64 addr{}; - std::size_t num_pages{}; - }; - -public: - PageLinkedList() = default; - PageLinkedList(u64 address, u64 num_pages) { - ASSERT(AddBlock(address, num_pages).IsSuccess()); - } - - constexpr std::list<Node>& Nodes() { - return nodes; - } - - constexpr const std::list<Node>& Nodes() const { - return nodes; - } - - std::size_t GetNumPages() const { - std::size_t num_pages = 0; - for (const Node& node : nodes) { - num_pages += node.GetNumPages(); - } - return num_pages; - } - - bool IsEqual(PageLinkedList& other) const { - auto this_node = nodes.begin(); - auto other_node = other.nodes.begin(); - while (this_node != nodes.end() && other_node != other.nodes.end()) { - if (this_node->GetAddress() != other_node->GetAddress() || - this_node->GetNumPages() != other_node->GetNumPages()) { - return false; - } - this_node = std::next(this_node); - other_node = std::next(other_node); - } - - return this_node == nodes.end() && other_node == other.nodes.end(); - } - - ResultCode AddBlock(u64 address, u64 num_pages) { - if (!num_pages) { - return RESULT_SUCCESS; - } - if (!nodes.empty()) { - const auto node = nodes.back(); - if (node.GetAddress() + node.GetNumPages() * PageSize == address) { - address = node.GetAddress(); - num_pages += node.GetNumPages(); - nodes.pop_back(); - } - } - nodes.push_back({address, num_pages}); - return RESULT_SUCCESS; - } - -private: - std::list<Node> nodes; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp deleted file mode 100644 index 00ed9b881..000000000 --- a/src/core/hle/kernel/memory/page_table.cpp +++ /dev/null @@ -1,1184 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/scope_exit.h" -#include "core/core.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/address_space_info.h" -#include "core/hle/kernel/memory/memory_block.h" -#include "core/hle/kernel/memory/memory_block_manager.h" -#include "core/hle/kernel/memory/page_linked_list.h" -#include "core/hle/kernel/memory/page_table.h" -#include "core/hle/kernel/memory/system_control.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/svc_results.h" -#include "core/memory.h" - -namespace Kernel::Memory { - -namespace { - -constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType as_type) { - switch (as_type) { - case FileSys::ProgramAddressSpaceType::Is32Bit: - case FileSys::ProgramAddressSpaceType::Is32BitNoMap: - return 32; - case FileSys::ProgramAddressSpaceType::Is36Bit: - return 36; - case FileSys::ProgramAddressSpaceType::Is39Bit: - return 39; - default: - UNREACHABLE(); - return {}; - } -} - -constexpr u64 GetAddressInRange(const MemoryInfo& info, VAddr addr) { - if (info.GetAddress() < addr) { - return addr; - } - return info.GetAddress(); -} - -constexpr std::size_t GetSizeInRange(const MemoryInfo& info, VAddr start, VAddr end) { - std::size_t size{info.GetSize()}; - if (info.GetAddress() < start) { - size -= start - info.GetAddress(); - } - if (info.GetEndAddress() > end) { - size -= info.GetEndAddress() - end; - } - return size; -} - -} // namespace - -PageTable::PageTable(Core::System& system) : system{system} {} - -ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, - bool enable_aslr, VAddr code_addr, std::size_t code_size, - Memory::MemoryManager::Pool pool) { - - const auto GetSpaceStart = [this](AddressSpaceInfo::Type type) { - return AddressSpaceInfo::GetAddressSpaceStart(address_space_width, type); - }; - const auto GetSpaceSize = [this](AddressSpaceInfo::Type type) { - return AddressSpaceInfo::GetAddressSpaceSize(address_space_width, type); - }; - - // Set our width and heap/alias sizes - address_space_width = GetAddressSpaceWidthFromType(as_type); - const VAddr start = 0; - const VAddr end{1ULL << address_space_width}; - std::size_t alias_region_size{GetSpaceSize(AddressSpaceInfo::Type::Alias)}; - std::size_t heap_region_size{GetSpaceSize(AddressSpaceInfo::Type::Heap)}; - - ASSERT(start <= code_addr); - ASSERT(code_addr < code_addr + code_size); - ASSERT(code_addr + code_size - 1 <= end - 1); - - // Adjust heap/alias size if we don't have an alias region - if (as_type == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { - heap_region_size += alias_region_size; - alias_region_size = 0; - } - - // Set code regions and determine remaining - constexpr std::size_t RegionAlignment{2 * 1024 * 1024}; - VAddr process_code_start{}; - VAddr process_code_end{}; - std::size_t stack_region_size{}; - std::size_t kernel_map_region_size{}; - - if (address_space_width == 39) { - alias_region_size = GetSpaceSize(AddressSpaceInfo::Type::Alias); - heap_region_size = GetSpaceSize(AddressSpaceInfo::Type::Heap); - stack_region_size = GetSpaceSize(AddressSpaceInfo::Type::Stack); - kernel_map_region_size = GetSpaceSize(AddressSpaceInfo::Type::Is32Bit); - code_region_start = GetSpaceStart(AddressSpaceInfo::Type::Large64Bit); - code_region_end = code_region_start + GetSpaceSize(AddressSpaceInfo::Type::Large64Bit); - alias_code_region_start = code_region_start; - alias_code_region_end = code_region_end; - process_code_start = Common::AlignDown(code_addr, RegionAlignment); - process_code_end = Common::AlignUp(code_addr + code_size, RegionAlignment); - } else { - stack_region_size = 0; - kernel_map_region_size = 0; - code_region_start = GetSpaceStart(AddressSpaceInfo::Type::Is32Bit); - code_region_end = code_region_start + GetSpaceSize(AddressSpaceInfo::Type::Is32Bit); - stack_region_start = code_region_start; - alias_code_region_start = code_region_start; - alias_code_region_end = GetSpaceStart(AddressSpaceInfo::Type::Small64Bit) + - GetSpaceSize(AddressSpaceInfo::Type::Small64Bit); - stack_region_end = code_region_end; - kernel_map_region_start = code_region_start; - kernel_map_region_end = code_region_end; - process_code_start = code_region_start; - process_code_end = code_region_end; - } - - // Set other basic fields - is_aslr_enabled = enable_aslr; - address_space_start = start; - address_space_end = end; - is_kernel = false; - - // Determine the region we can place our undetermineds in - VAddr alloc_start{}; - std::size_t alloc_size{}; - if ((process_code_start - code_region_start) >= (end - process_code_end)) { - alloc_start = code_region_start; - alloc_size = process_code_start - code_region_start; - } else { - alloc_start = process_code_end; - alloc_size = end - process_code_end; - } - const std::size_t needed_size{ - (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)}; - if (alloc_size < needed_size) { - UNREACHABLE(); - return ResultOutOfMemory; - } - - const std::size_t remaining_size{alloc_size - needed_size}; - - // Determine random placements for each region - std::size_t alias_rnd{}, heap_rnd{}, stack_rnd{}, kmap_rnd{}; - if (enable_aslr) { - alias_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - heap_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - stack_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - kmap_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - } - - // Setup heap and alias regions - alias_region_start = alloc_start + alias_rnd; - alias_region_end = alias_region_start + alias_region_size; - heap_region_start = alloc_start + heap_rnd; - heap_region_end = heap_region_start + heap_region_size; - - if (alias_rnd <= heap_rnd) { - heap_region_start += alias_region_size; - heap_region_end += alias_region_size; - } else { - alias_region_start += heap_region_size; - alias_region_end += heap_region_size; - } - - // Setup stack region - if (stack_region_size) { - stack_region_start = alloc_start + stack_rnd; - stack_region_end = stack_region_start + stack_region_size; - - if (alias_rnd < stack_rnd) { - stack_region_start += alias_region_size; - stack_region_end += alias_region_size; - } else { - alias_region_start += stack_region_size; - alias_region_end += stack_region_size; - } - - if (heap_rnd < stack_rnd) { - stack_region_start += heap_region_size; - stack_region_end += heap_region_size; - } else { - heap_region_start += stack_region_size; - heap_region_end += stack_region_size; - } - } - - // Setup kernel map region - if (kernel_map_region_size) { - kernel_map_region_start = alloc_start + kmap_rnd; - kernel_map_region_end = kernel_map_region_start + kernel_map_region_size; - - if (alias_rnd < kmap_rnd) { - kernel_map_region_start += alias_region_size; - kernel_map_region_end += alias_region_size; - } else { - alias_region_start += kernel_map_region_size; - alias_region_end += kernel_map_region_size; - } - - if (heap_rnd < kmap_rnd) { - kernel_map_region_start += heap_region_size; - kernel_map_region_end += heap_region_size; - } else { - heap_region_start += kernel_map_region_size; - heap_region_end += kernel_map_region_size; - } - - if (stack_region_size) { - if (stack_rnd < kmap_rnd) { - kernel_map_region_start += stack_region_size; - kernel_map_region_end += stack_region_size; - } else { - stack_region_start += kernel_map_region_size; - stack_region_end += kernel_map_region_size; - } - } - } - - // Set heap members - current_heap_end = heap_region_start; - max_heap_size = 0; - max_physical_memory_size = 0; - - // Ensure that we regions inside our address space - auto IsInAddressSpace = [&](VAddr addr) { - return address_space_start <= addr && addr <= address_space_end; - }; - ASSERT(IsInAddressSpace(alias_region_start)); - ASSERT(IsInAddressSpace(alias_region_end)); - ASSERT(IsInAddressSpace(heap_region_start)); - ASSERT(IsInAddressSpace(heap_region_end)); - ASSERT(IsInAddressSpace(stack_region_start)); - ASSERT(IsInAddressSpace(stack_region_end)); - ASSERT(IsInAddressSpace(kernel_map_region_start)); - ASSERT(IsInAddressSpace(kernel_map_region_end)); - - // Ensure that we selected regions that don't overlap - const VAddr alias_start{alias_region_start}; - const VAddr alias_last{alias_region_end - 1}; - const VAddr heap_start{heap_region_start}; - const VAddr heap_last{heap_region_end - 1}; - const VAddr stack_start{stack_region_start}; - const VAddr stack_last{stack_region_end - 1}; - const VAddr kmap_start{kernel_map_region_start}; - const VAddr kmap_last{kernel_map_region_end - 1}; - ASSERT(alias_last < heap_start || heap_last < alias_start); - ASSERT(alias_last < stack_start || stack_last < alias_start); - ASSERT(alias_last < kmap_start || kmap_last < alias_start); - ASSERT(heap_last < stack_start || stack_last < heap_start); - ASSERT(heap_last < kmap_start || kmap_last < heap_start); - - current_heap_addr = heap_region_start; - heap_capacity = 0; - physical_memory_usage = 0; - memory_pool = pool; - - page_table_impl.Resize(address_space_width, PageBits); - - return InitializeMemoryLayout(start, end); -} - -ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, MemoryState state, - MemoryPermission perm) { - std::lock_guard lock{page_table_lock}; - - const u64 size{num_pages * PageSize}; - - if (!CanContain(addr, size, state)) { - return ResultInvalidCurrentMemory; - } - - if (IsRegionMapped(addr, size)) { - return ResultInvalidCurrentMemory; - } - - PageLinkedList page_linked_list; - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); - CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup)); - - block_manager->Update(addr, num_pages, state, perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - const std::size_t num_pages{size / PageSize}; - - MemoryState state{}; - MemoryPermission perm{}; - CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, MemoryState::All, - MemoryState::Normal, MemoryPermission::Mask, - MemoryPermission::ReadAndWrite, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); - - if (IsRegionMapped(dst_addr, size)) { - return ResultInvalidCurrentMemory; - } - - PageLinkedList page_linked_list; - AddRegionToPages(src_addr, num_pages, page_linked_list); - - { - auto block_guard = detail::ScopeExit( - [&] { Operate(src_addr, num_pages, perm, OperationType::ChangePermissions); }); - - CASCADE_CODE( - Operate(src_addr, num_pages, MemoryPermission::None, OperationType::ChangePermissions)); - CASCADE_CODE(MapPages(dst_addr, page_linked_list, MemoryPermission::None)); - - block_guard.Cancel(); - } - - block_manager->Update(src_addr, num_pages, state, MemoryPermission::None, - MemoryAttribute::Locked); - block_manager->Update(dst_addr, num_pages, MemoryState::AliasCode); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - if (!size) { - return RESULT_SUCCESS; - } - - const std::size_t num_pages{size / PageSize}; - - CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, MemoryState::All, - MemoryState::Normal, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::Locked, MemoryAttribute::IpcAndDeviceMapped)); - - MemoryState state{}; - CASCADE_CODE(CheckMemoryState( - &state, nullptr, nullptr, dst_addr, PageSize, MemoryState::FlagCanCodeAlias, - MemoryState::FlagCanCodeAlias, MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::Mask, MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); - CASCADE_CODE(CheckMemoryState(dst_addr, size, MemoryState::All, state, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None)); - CASCADE_CODE(Operate(dst_addr, num_pages, MemoryPermission::None, OperationType::Unmap)); - - block_manager->Update(dst_addr, num_pages, MemoryState::Free); - block_manager->Update(src_addr, num_pages, MemoryState::Normal, MemoryPermission::ReadAndWrite); - - return RESULT_SUCCESS; -} - -void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end) { - auto node{page_linked_list.Nodes().begin()}; - PAddr map_addr{node->GetAddress()}; - std::size_t src_num_pages{node->GetNumPages()}; - - block_manager->IterateForRange(start, end, [&](const MemoryInfo& info) { - if (info.state != MemoryState::Free) { - return; - } - - std::size_t dst_num_pages{GetSizeInRange(info, start, end) / PageSize}; - VAddr dst_addr{GetAddressInRange(info, start)}; - - while (dst_num_pages) { - if (!src_num_pages) { - node = std::next(node); - map_addr = node->GetAddress(); - src_num_pages = node->GetNumPages(); - } - - const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; - Operate(dst_addr, num_pages, MemoryPermission::ReadAndWrite, OperationType::Map, - map_addr); - - dst_addr += num_pages * PageSize; - map_addr += num_pages * PageSize; - src_num_pages -= num_pages; - dst_num_pages -= num_pages; - } - }); -} - -ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - std::size_t mapped_size{}; - const VAddr end_addr{addr + size}; - - block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) { - if (info.state != MemoryState::Free) { - mapped_size += GetSizeInRange(info, addr, end_addr); - } - }); - - if (mapped_size == size) { - return RESULT_SUCCESS; - } - - const std::size_t remaining_size{size - mapped_size}; - const std::size_t remaining_pages{remaining_size / PageSize}; - - // Reserve the memory from the process resource limit. - KScopedResourceReservation memory_reservation( - system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, - remaining_size); - if (!memory_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); - return ResultResourceLimitedExceeded; - } - - PageLinkedList page_linked_list; - - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool)); - - // We succeeded, so commit the memory reservation. - memory_reservation.Commit(); - - MapPhysicalMemory(page_linked_list, addr, end_addr); - - physical_memory_usage += remaining_size; - - const std::size_t num_pages{size / PageSize}; - block_manager->Update(addr, num_pages, MemoryState::Free, MemoryPermission::None, - MemoryAttribute::None, MemoryState::Normal, - MemoryPermission::ReadAndWrite, MemoryAttribute::None); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - const VAddr end_addr{addr + size}; - ResultCode result{RESULT_SUCCESS}; - std::size_t mapped_size{}; - - // Verify that the region can be unmapped - block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) { - if (info.state == MemoryState::Normal) { - if (info.attribute != MemoryAttribute::None) { - result = ResultInvalidCurrentMemory; - return; - } - mapped_size += GetSizeInRange(info, addr, end_addr); - } else if (info.state != MemoryState::Free) { - result = ResultInvalidCurrentMemory; - } - }); - - if (result.IsError()) { - return result; - } - - if (!mapped_size) { - return RESULT_SUCCESS; - } - - CASCADE_CODE(UnmapMemory(addr, size)); - - auto process{system.Kernel().CurrentProcess()}; - process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); - physical_memory_usage -= mapped_size; - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - const VAddr end_addr{addr + size}; - ResultCode result{RESULT_SUCCESS}; - PageLinkedList page_linked_list; - - // Unmap each region within the range - block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) { - if (info.state == MemoryState::Normal) { - const std::size_t block_size{GetSizeInRange(info, addr, end_addr)}; - const std::size_t block_num_pages{block_size / PageSize}; - const VAddr block_addr{GetAddressInRange(info, addr)}; - - AddRegionToPages(block_addr, block_size / PageSize, page_linked_list); - - if (result = Operate(block_addr, block_num_pages, MemoryPermission::None, - OperationType::Unmap); - result.IsError()) { - return; - } - } - }); - - if (result.IsError()) { - return result; - } - - const std::size_t num_pages{size / PageSize}; - system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool); - - block_manager->Update(addr, num_pages, MemoryState::Free); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - MemoryState src_state{}; - CASCADE_CODE(CheckMemoryState( - &src_state, nullptr, nullptr, src_addr, size, MemoryState::FlagCanAlias, - MemoryState::FlagCanAlias, MemoryPermission::Mask, MemoryPermission::ReadAndWrite, - MemoryAttribute::Mask, MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); - - if (IsRegionMapped(dst_addr, size)) { - return ResultInvalidCurrentMemory; - } - - PageLinkedList page_linked_list; - const std::size_t num_pages{size / PageSize}; - - AddRegionToPages(src_addr, num_pages, page_linked_list); - - { - auto block_guard = detail::ScopeExit([&] { - Operate(src_addr, num_pages, MemoryPermission::ReadAndWrite, - OperationType::ChangePermissions); - }); - - CASCADE_CODE( - Operate(src_addr, num_pages, MemoryPermission::None, OperationType::ChangePermissions)); - CASCADE_CODE(MapPages(dst_addr, page_linked_list, MemoryPermission::ReadAndWrite)); - - block_guard.Cancel(); - } - - block_manager->Update(src_addr, num_pages, src_state, MemoryPermission::None, - MemoryAttribute::Locked); - block_manager->Update(dst_addr, num_pages, MemoryState::Stack, MemoryPermission::ReadAndWrite); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - MemoryState src_state{}; - CASCADE_CODE(CheckMemoryState( - &src_state, nullptr, nullptr, src_addr, size, MemoryState::FlagCanAlias, - MemoryState::FlagCanAlias, MemoryPermission::Mask, MemoryPermission::None, - MemoryAttribute::Mask, MemoryAttribute::Locked, MemoryAttribute::IpcAndDeviceMapped)); - - MemoryPermission dst_perm{}; - CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, MemoryState::All, - MemoryState::Stack, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); - - PageLinkedList src_pages; - PageLinkedList dst_pages; - const std::size_t num_pages{size / PageSize}; - - AddRegionToPages(src_addr, num_pages, src_pages); - AddRegionToPages(dst_addr, num_pages, dst_pages); - - if (!dst_pages.IsEqual(src_pages)) { - return ResultInvalidMemoryRange; - } - - { - auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); }); - - CASCADE_CODE(Operate(dst_addr, num_pages, MemoryPermission::None, OperationType::Unmap)); - CASCADE_CODE(Operate(src_addr, num_pages, MemoryPermission::ReadAndWrite, - OperationType::ChangePermissions)); - - block_guard.Cancel(); - } - - block_manager->Update(src_addr, num_pages, src_state, MemoryPermission::ReadAndWrite); - block_manager->Update(dst_addr, num_pages, MemoryState::Free); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_list, - MemoryPermission perm) { - VAddr cur_addr{addr}; - - for (const auto& node : page_linked_list.Nodes()) { - if (const auto result{ - Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())}; - result.IsError()) { - const std::size_t num_pages{(addr - cur_addr) / PageSize}; - - ASSERT( - Operate(addr, num_pages, MemoryPermission::None, OperationType::Unmap).IsSuccess()); - - return result; - } - - cur_addr += node.GetNumPages() * PageSize; - } - - return RESULT_SUCCESS; -} - -ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state, - MemoryPermission perm) { - std::lock_guard lock{page_table_lock}; - - const std::size_t num_pages{page_linked_list.GetNumPages()}; - const std::size_t size{num_pages * PageSize}; - - if (!CanContain(addr, size, state)) { - return ResultInvalidCurrentMemory; - } - - if (IsRegionMapped(addr, num_pages * PageSize)) { - return ResultInvalidCurrentMemory; - } - - CASCADE_CODE(MapPages(addr, page_linked_list, perm)); - - block_manager->Update(addr, num_pages, state, perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm) { - - std::lock_guard lock{page_table_lock}; - - MemoryState prev_state{}; - MemoryPermission prev_perm{}; - - CASCADE_CODE(CheckMemoryState( - &prev_state, &prev_perm, nullptr, addr, size, MemoryState::FlagCode, MemoryState::FlagCode, - MemoryPermission::None, MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); - - MemoryState state{prev_state}; - - // Ensure state is mutable if permission allows write - if ((perm & MemoryPermission::Write) != MemoryPermission::None) { - if (prev_state == MemoryState::Code) { - state = MemoryState::CodeData; - } else if (prev_state == MemoryState::AliasCode) { - state = MemoryState::AliasCodeData; - } else { - UNREACHABLE(); - } - } - - // Return early if there is nothing to change - if (state == prev_state && perm == prev_perm) { - return RESULT_SUCCESS; - } - - if ((prev_perm & MemoryPermission::Execute) != (perm & MemoryPermission::Execute)) { - // Memory execution state is changing, invalidate CPU cache range - system.InvalidateCpuInstructionCacheRange(addr, size); - } - - const std::size_t num_pages{size / PageSize}; - const OperationType operation{(perm & MemoryPermission::Execute) != MemoryPermission::None - ? OperationType::ChangePermissionsAndRefresh - : OperationType::ChangePermissions}; - - CASCADE_CODE(Operate(addr, num_pages, perm, operation)); - - block_manager->Update(addr, num_pages, state, perm); - - return RESULT_SUCCESS; -} - -MemoryInfo PageTable::QueryInfoImpl(VAddr addr) { - std::lock_guard lock{page_table_lock}; - - return block_manager->FindBlock(addr).GetMemoryInfo(); -} - -MemoryInfo PageTable::QueryInfo(VAddr addr) { - if (!Contains(addr, 1)) { - return {address_space_end, 0 - address_space_end, MemoryState::Inaccessible, - MemoryPermission::None, MemoryAttribute::None, MemoryPermission::None}; - } - - return QueryInfoImpl(addr); -} - -ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm) { - std::lock_guard lock{page_table_lock}; - - MemoryState state{}; - MemoryAttribute attribute{}; - - CASCADE_CODE(CheckMemoryState(&state, nullptr, &attribute, addr, size, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryPermission::Mask, MemoryPermission::ReadAndWrite, - MemoryAttribute::Mask, MemoryAttribute::None, - MemoryAttribute::IpcAndDeviceMapped)); - - block_manager->Update(addr, size / PageSize, state, perm, attribute | MemoryAttribute::Locked); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::ResetTransferMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - MemoryState state{}; - - CASCADE_CODE(CheckMemoryState(&state, nullptr, nullptr, addr, size, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::Mask, MemoryAttribute::Locked, - MemoryAttribute::IpcAndDeviceMapped)); - - block_manager->Update(addr, size / PageSize, state, MemoryPermission::ReadAndWrite); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask, - MemoryAttribute value) { - std::lock_guard lock{page_table_lock}; - - MemoryState state{}; - MemoryPermission perm{}; - MemoryAttribute attribute{}; - - CASCADE_CODE(CheckMemoryState(&state, &perm, &attribute, addr, size, - MemoryState::FlagCanChangeAttribute, - MemoryState::FlagCanChangeAttribute, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::LockedAndIpcLocked, - MemoryAttribute::None, MemoryAttribute::DeviceSharedAndUncached)); - - attribute = attribute & ~mask; - attribute = attribute | (mask & value); - - block_manager->Update(addr, size / PageSize, state, perm, attribute); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::SetHeapCapacity(std::size_t new_heap_capacity) { - std::lock_guard lock{page_table_lock}; - heap_capacity = new_heap_capacity; - return RESULT_SUCCESS; -} - -ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) { - - if (size > heap_region_end - heap_region_start) { - return ResultOutOfMemory; - } - - const u64 previous_heap_size{GetHeapSize()}; - - UNIMPLEMENTED_IF_MSG(previous_heap_size > size, "Heap shrink is unimplemented"); - - // Increase the heap size - { - std::lock_guard lock{page_table_lock}; - - const u64 delta{size - previous_heap_size}; - - // Reserve memory for the heap extension. - KScopedResourceReservation memory_reservation( - system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, - delta); - - if (!memory_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); - return ResultResourceLimitedExceeded; - } - - PageLinkedList page_linked_list; - const std::size_t num_pages{delta / PageSize}; - - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); - - if (IsRegionMapped(current_heap_addr, delta)) { - return ResultInvalidCurrentMemory; - } - - CASCADE_CODE( - Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); - - // Succeeded in allocation, commit the resource reservation - memory_reservation.Commit(); - - block_manager->Update(current_heap_addr, num_pages, MemoryState::Normal, - MemoryPermission::ReadAndWrite); - - current_heap_addr = heap_region_start + size; - } - - return MakeResult<VAddr>(heap_region_start); -} - -ResultVal<VAddr> PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, - bool is_map_only, VAddr region_start, - std::size_t region_num_pages, MemoryState state, - MemoryPermission perm, PAddr map_addr) { - std::lock_guard lock{page_table_lock}; - - if (!CanContain(region_start, region_num_pages * PageSize, state)) { - return ResultInvalidCurrentMemory; - } - - if (region_num_pages <= needed_num_pages) { - return ResultOutOfMemory; - } - - const VAddr addr{ - AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)}; - if (!addr) { - return ResultOutOfMemory; - } - - if (is_map_only) { - CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); - } else { - PageLinkedList page_group; - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool)); - CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); - } - - block_manager->Update(addr, needed_num_pages, state, perm); - - return MakeResult<VAddr>(addr); -} - -ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - MemoryPermission perm{}; - if (const ResultCode result{CheckMemoryState( - nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute, - MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None, - MemoryAttribute::DeviceSharedAndUncached)}; - result.IsError()) { - return result; - } - - block_manager->UpdateLock( - addr, size / PageSize, - [](MemoryBlockManager::iterator block, MemoryPermission perm) { - block->ShareToDevice(perm); - }, - perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - MemoryPermission perm{}; - if (const ResultCode result{CheckMemoryState( - nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute, - MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None, - MemoryAttribute::DeviceSharedAndUncached)}; - result.IsError()) { - return result; - } - - block_manager->UpdateLock( - addr, size / PageSize, - [](MemoryBlockManager::iterator block, MemoryPermission perm) { - block->UnshareToDevice(perm); - }, - perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::InitializeMemoryLayout(VAddr start, VAddr end) { - block_manager = std::make_unique<MemoryBlockManager>(start, end); - - return RESULT_SUCCESS; -} - -bool PageTable::IsRegionMapped(VAddr address, u64 size) { - return CheckMemoryState(address, size, MemoryState::All, MemoryState::Free, - MemoryPermission::Mask, MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped) - .IsError(); -} - -bool PageTable::IsRegionContiguous(VAddr addr, u64 size) const { - auto start_ptr = system.Memory().GetPointer(addr); - for (u64 offset{}; offset < size; offset += PageSize) { - if (start_ptr != system.Memory().GetPointer(addr + offset)) { - return false; - } - start_ptr += PageSize; - } - return true; -} - -void PageTable::AddRegionToPages(VAddr start, std::size_t num_pages, - PageLinkedList& page_linked_list) { - VAddr addr{start}; - while (addr < start + (num_pages * PageSize)) { - const PAddr paddr{GetPhysicalAddr(addr)}; - if (!paddr) { - UNREACHABLE(); - } - page_linked_list.AddBlock(paddr, 1); - addr += PageSize; - } -} - -VAddr PageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, - u64 needed_num_pages, std::size_t align) { - if (is_aslr_enabled) { - UNIMPLEMENTED(); - } - return block_manager->FindFreeArea(start, region_num_pages, needed_num_pages, align, 0, - IsKernel() ? 1 : 4); -} - -ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group, - OperationType operation) { - std::lock_guard lock{page_table_lock}; - - ASSERT(Common::IsAligned(addr, PageSize)); - ASSERT(num_pages > 0); - ASSERT(num_pages == page_group.GetNumPages()); - - for (const auto& node : page_group.Nodes()) { - const std::size_t size{node.GetNumPages() * PageSize}; - - switch (operation) { - case OperationType::MapGroup: - system.Memory().MapMemoryRegion(page_table_impl, addr, size, node.GetAddress()); - break; - default: - UNREACHABLE(); - } - - addr += size; - } - - return RESULT_SUCCESS; -} - -ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm, - OperationType operation, PAddr map_addr) { - std::lock_guard lock{page_table_lock}; - - ASSERT(num_pages > 0); - ASSERT(Common::IsAligned(addr, PageSize)); - ASSERT(ContainsPages(addr, num_pages)); - - switch (operation) { - case OperationType::Unmap: - system.Memory().UnmapRegion(page_table_impl, addr, num_pages * PageSize); - break; - case OperationType::Map: { - ASSERT(map_addr); - ASSERT(Common::IsAligned(map_addr, PageSize)); - system.Memory().MapMemoryRegion(page_table_impl, addr, num_pages * PageSize, map_addr); - break; - } - case OperationType::ChangePermissions: - case OperationType::ChangePermissionsAndRefresh: - break; - default: - UNREACHABLE(); - } - return RESULT_SUCCESS; -} - -constexpr VAddr PageTable::GetRegionAddress(MemoryState state) const { - switch (state) { - case MemoryState::Free: - case MemoryState::Kernel: - return address_space_start; - case MemoryState::Normal: - return heap_region_start; - case MemoryState::Ipc: - case MemoryState::NonSecureIpc: - case MemoryState::NonDeviceIpc: - return alias_region_start; - case MemoryState::Stack: - return stack_region_start; - case MemoryState::Io: - case MemoryState::Static: - case MemoryState::ThreadLocal: - return kernel_map_region_start; - case MemoryState::Shared: - case MemoryState::AliasCode: - case MemoryState::AliasCodeData: - case MemoryState::Transferred: - case MemoryState::SharedTransferred: - case MemoryState::SharedCode: - case MemoryState::GeneratedCode: - case MemoryState::CodeOut: - return alias_code_region_start; - case MemoryState::Code: - case MemoryState::CodeData: - return code_region_start; - default: - UNREACHABLE(); - return {}; - } -} - -constexpr std::size_t PageTable::GetRegionSize(MemoryState state) const { - switch (state) { - case MemoryState::Free: - case MemoryState::Kernel: - return address_space_end - address_space_start; - case MemoryState::Normal: - return heap_region_end - heap_region_start; - case MemoryState::Ipc: - case MemoryState::NonSecureIpc: - case MemoryState::NonDeviceIpc: - return alias_region_end - alias_region_start; - case MemoryState::Stack: - return stack_region_end - stack_region_start; - case MemoryState::Io: - case MemoryState::Static: - case MemoryState::ThreadLocal: - return kernel_map_region_end - kernel_map_region_start; - case MemoryState::Shared: - case MemoryState::AliasCode: - case MemoryState::AliasCodeData: - case MemoryState::Transferred: - case MemoryState::SharedTransferred: - case MemoryState::SharedCode: - case MemoryState::GeneratedCode: - case MemoryState::CodeOut: - return alias_code_region_end - alias_code_region_start; - case MemoryState::Code: - case MemoryState::CodeData: - return code_region_end - code_region_start; - default: - UNREACHABLE(); - return {}; - } -} - -constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState state) const { - const VAddr end{addr + size}; - const VAddr last{end - 1}; - const VAddr region_start{GetRegionAddress(state)}; - const std::size_t region_size{GetRegionSize(state)}; - const bool is_in_region{region_start <= addr && addr < end && - last <= region_start + region_size - 1}; - const bool is_in_heap{!(end <= heap_region_start || heap_region_end <= addr)}; - const bool is_in_alias{!(end <= alias_region_start || alias_region_end <= addr)}; - - switch (state) { - case MemoryState::Free: - case MemoryState::Kernel: - return is_in_region; - case MemoryState::Io: - case MemoryState::Static: - case MemoryState::Code: - case MemoryState::CodeData: - case MemoryState::Shared: - case MemoryState::AliasCode: - case MemoryState::AliasCodeData: - case MemoryState::Stack: - case MemoryState::ThreadLocal: - case MemoryState::Transferred: - case MemoryState::SharedTransferred: - case MemoryState::SharedCode: - case MemoryState::GeneratedCode: - case MemoryState::CodeOut: - return is_in_region && !is_in_heap && !is_in_alias; - case MemoryState::Normal: - ASSERT(is_in_heap); - return is_in_region && !is_in_alias; - case MemoryState::Ipc: - case MemoryState::NonSecureIpc: - case MemoryState::NonDeviceIpc: - ASSERT(is_in_alias); - return is_in_region && !is_in_heap; - default: - return false; - } -} - -constexpr ResultCode PageTable::CheckMemoryState(const MemoryInfo& info, MemoryState state_mask, - MemoryState state, MemoryPermission perm_mask, - MemoryPermission perm, MemoryAttribute attr_mask, - MemoryAttribute attr) const { - // Validate the states match expectation - if ((info.state & state_mask) != state) { - return ResultInvalidCurrentMemory; - } - if ((info.perm & perm_mask) != perm) { - return ResultInvalidCurrentMemory; - } - if ((info.attribute & attr_mask) != attr) { - return ResultInvalidCurrentMemory; - } - - return RESULT_SUCCESS; -} - -ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission* out_perm, - MemoryAttribute* out_attr, VAddr addr, std::size_t size, - MemoryState state_mask, MemoryState state, - MemoryPermission perm_mask, MemoryPermission perm, - MemoryAttribute attr_mask, MemoryAttribute attr, - MemoryAttribute ignore_attr) { - std::lock_guard lock{page_table_lock}; - - // Get information about the first block - const VAddr last_addr{addr + size - 1}; - MemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; - MemoryInfo info{it->GetMemoryInfo()}; - - // Validate all blocks in the range have correct state - const MemoryState first_state{info.state}; - const MemoryPermission first_perm{info.perm}; - const MemoryAttribute first_attr{info.attribute}; - - while (true) { - // Validate the current block - if (!(info.state == first_state)) { - return ResultInvalidCurrentMemory; - } - if (!(info.perm == first_perm)) { - return ResultInvalidCurrentMemory; - } - if (!((info.attribute | static_cast<MemoryAttribute>(ignore_attr)) == - (first_attr | static_cast<MemoryAttribute>(ignore_attr)))) { - return ResultInvalidCurrentMemory; - } - - // Validate against the provided masks - CASCADE_CODE(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); - - // Break once we're done - if (last_addr <= info.GetLastAddress()) { - break; - } - - // Advance our iterator - it++; - ASSERT(it != block_manager->cend()); - info = it->GetMemoryInfo(); - } - - // Write output state - if (out_state) { - *out_state = first_state; - } - if (out_perm) { - *out_perm = first_perm; - } - if (out_attr) { - *out_attr = first_attr & static_cast<MemoryAttribute>(~ignore_attr); - } - - return RESULT_SUCCESS; -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/memory/page_table.h deleted file mode 100644 index ce0d38849..000000000 --- a/src/core/hle/kernel/memory/page_table.h +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <mutex> - -#include "common/common_types.h" -#include "common/page_table.h" -#include "core/file_sys/program_metadata.h" -#include "core/hle/kernel/memory/memory_block.h" -#include "core/hle/kernel/memory/memory_manager.h" -#include "core/hle/result.h" - -namespace Core { -class System; -} - -namespace Kernel::Memory { - -class MemoryBlockManager; - -class PageTable final : NonCopyable { -public: - explicit PageTable(Core::System& system); - - ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, - VAddr code_addr, std::size_t code_size, - Memory::MemoryManager::Pool pool); - ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, MemoryState state, - MemoryPermission perm); - ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); - ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size); - ResultCode UnmapMemory(VAddr addr, std::size_t size); - ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state, - MemoryPermission perm); - ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm); - MemoryInfo QueryInfo(VAddr addr); - ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm); - ResultCode ResetTransferMemory(VAddr addr, std::size_t size); - ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask, - MemoryAttribute value); - ResultCode SetHeapCapacity(std::size_t new_heap_capacity); - ResultVal<VAddr> SetHeapSize(std::size_t size); - ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, - bool is_map_only, VAddr region_start, - std::size_t region_num_pages, MemoryState state, - MemoryPermission perm, PAddr map_addr = 0); - ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); - ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); - - Common::PageTable& PageTableImpl() { - return page_table_impl; - } - - const Common::PageTable& PageTableImpl() const { - return page_table_impl; - } - -private: - enum class OperationType : u32 { - Map, - MapGroup, - Unmap, - ChangePermissions, - ChangePermissionsAndRefresh, - }; - - static constexpr MemoryAttribute DefaultMemoryIgnoreAttr = - MemoryAttribute::DontCareMask | MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared; - - ResultCode InitializeMemoryLayout(VAddr start, VAddr end); - ResultCode MapPages(VAddr addr, const PageLinkedList& page_linked_list, MemoryPermission perm); - void MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end); - bool IsRegionMapped(VAddr address, u64 size); - bool IsRegionContiguous(VAddr addr, u64 size) const; - void AddRegionToPages(VAddr start, std::size_t num_pages, PageLinkedList& page_linked_list); - MemoryInfo QueryInfoImpl(VAddr addr); - VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages, - std::size_t align); - ResultCode Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group, - OperationType operation); - ResultCode Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm, - OperationType operation, PAddr map_addr = 0); - constexpr VAddr GetRegionAddress(MemoryState state) const; - constexpr std::size_t GetRegionSize(MemoryState state) const; - constexpr bool CanContain(VAddr addr, std::size_t size, MemoryState state) const; - - constexpr ResultCode CheckMemoryState(const MemoryInfo& info, MemoryState state_mask, - MemoryState state, MemoryPermission perm_mask, - MemoryPermission perm, MemoryAttribute attr_mask, - MemoryAttribute attr) const; - ResultCode CheckMemoryState(MemoryState* out_state, MemoryPermission* out_perm, - MemoryAttribute* out_attr, VAddr addr, std::size_t size, - MemoryState state_mask, MemoryState state, - MemoryPermission perm_mask, MemoryPermission perm, - MemoryAttribute attr_mask, MemoryAttribute attr, - MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr); - ResultCode CheckMemoryState(VAddr addr, std::size_t size, MemoryState state_mask, - MemoryState state, MemoryPermission perm_mask, - MemoryPermission perm, MemoryAttribute attr_mask, - MemoryAttribute attr, - MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) { - return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, - perm, attr_mask, attr, ignore_attr); - } - - std::recursive_mutex page_table_lock; - std::unique_ptr<MemoryBlockManager> block_manager; - -public: - constexpr VAddr GetAddressSpaceStart() const { - return address_space_start; - } - constexpr VAddr GetAddressSpaceEnd() const { - return address_space_end; - } - constexpr std::size_t GetAddressSpaceSize() const { - return address_space_end - address_space_start; - } - constexpr VAddr GetHeapRegionStart() const { - return heap_region_start; - } - constexpr VAddr GetHeapRegionEnd() const { - return heap_region_end; - } - constexpr std::size_t GetHeapRegionSize() const { - return heap_region_end - heap_region_start; - } - constexpr VAddr GetAliasRegionStart() const { - return alias_region_start; - } - constexpr VAddr GetAliasRegionEnd() const { - return alias_region_end; - } - constexpr std::size_t GetAliasRegionSize() const { - return alias_region_end - alias_region_start; - } - constexpr VAddr GetStackRegionStart() const { - return stack_region_start; - } - constexpr VAddr GetStackRegionEnd() const { - return stack_region_end; - } - constexpr std::size_t GetStackRegionSize() const { - return stack_region_end - stack_region_start; - } - constexpr VAddr GetKernelMapRegionStart() const { - return kernel_map_region_start; - } - constexpr VAddr GetKernelMapRegionEnd() const { - return kernel_map_region_end; - } - constexpr VAddr GetCodeRegionStart() const { - return code_region_start; - } - constexpr VAddr GetCodeRegionEnd() const { - return code_region_end; - } - constexpr VAddr GetAliasCodeRegionStart() const { - return alias_code_region_start; - } - constexpr VAddr GetAliasCodeRegionSize() const { - return alias_code_region_end - alias_code_region_start; - } - constexpr std::size_t GetAddressSpaceWidth() const { - return address_space_width; - } - constexpr std::size_t GetHeapSize() { - return current_heap_addr - heap_region_start; - } - constexpr std::size_t GetTotalHeapSize() { - return GetHeapSize() + physical_memory_usage; - } - constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const { - return address_space_start <= address && address + size - 1 <= address_space_end - 1; - } - constexpr bool IsOutsideAliasRegion(VAddr address, std::size_t size) const { - return alias_region_start > address || address + size - 1 > alias_region_end - 1; - } - constexpr bool IsOutsideStackRegion(VAddr address, std::size_t size) const { - return stack_region_start > address || address + size - 1 > stack_region_end - 1; - } - constexpr bool IsInvalidRegion(VAddr address, std::size_t size) const { - return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1; - } - constexpr bool IsInsideHeapRegion(VAddr address, std::size_t size) const { - return address + size > heap_region_start && heap_region_end > address; - } - constexpr bool IsInsideAliasRegion(VAddr address, std::size_t size) const { - return address + size > alias_region_start && alias_region_end > address; - } - constexpr bool IsOutsideASLRRegion(VAddr address, std::size_t size) const { - if (IsInvalidRegion(address, size)) { - return true; - } - if (IsInsideHeapRegion(address, size)) { - return true; - } - if (IsInsideAliasRegion(address, size)) { - return true; - } - return {}; - } - constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const { - return !IsOutsideASLRRegion(address, size); - } - constexpr PAddr GetPhysicalAddr(VAddr addr) { - return page_table_impl.backing_addr[addr >> Memory::PageBits] + addr; - } - -private: - constexpr bool Contains(VAddr addr) const { - return address_space_start <= addr && addr <= address_space_end - 1; - } - constexpr bool Contains(VAddr addr, std::size_t size) const { - return address_space_start <= addr && addr < addr + size && - addr + size - 1 <= address_space_end - 1; - } - constexpr bool IsKernel() const { - return is_kernel; - } - constexpr bool IsAslrEnabled() const { - return is_aslr_enabled; - } - - constexpr std::size_t GetNumGuardPages() const { - return IsKernel() ? 1 : 4; - } - - constexpr bool ContainsPages(VAddr addr, std::size_t num_pages) const { - return (address_space_start <= addr) && - (num_pages <= (address_space_end - address_space_start) / PageSize) && - (addr + num_pages * PageSize - 1 <= address_space_end - 1); - } - -private: - VAddr address_space_start{}; - VAddr address_space_end{}; - VAddr heap_region_start{}; - VAddr heap_region_end{}; - VAddr current_heap_end{}; - VAddr alias_region_start{}; - VAddr alias_region_end{}; - VAddr stack_region_start{}; - VAddr stack_region_end{}; - VAddr kernel_map_region_start{}; - VAddr kernel_map_region_end{}; - VAddr code_region_start{}; - VAddr code_region_end{}; - VAddr alias_code_region_start{}; - VAddr alias_code_region_end{}; - VAddr current_heap_addr{}; - - std::size_t heap_capacity{}; - std::size_t physical_memory_usage{}; - std::size_t max_heap_size{}; - std::size_t max_physical_memory_size{}; - std::size_t address_space_width{}; - - bool is_kernel{}; - bool is_aslr_enabled{}; - - MemoryManager::Pool memory_pool{MemoryManager::Pool::Application}; - - Common::PageTable page_table_impl; - - Core::System& system; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/slab_heap.h b/src/core/hle/kernel/memory/slab_heap.h deleted file mode 100644 index 465eaddb3..000000000 --- a/src/core/hle/kernel/memory/slab_heap.h +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#pragma once - -#include <atomic> - -#include "common/assert.h" -#include "common/common_types.h" - -namespace Kernel::Memory { - -namespace impl { - -class SlabHeapImpl final : NonCopyable { -public: - struct Node { - Node* next{}; - }; - - constexpr SlabHeapImpl() = default; - - void Initialize(std::size_t size) { - ASSERT(head == nullptr); - obj_size = size; - } - - constexpr std::size_t GetObjectSize() const { - return obj_size; - } - - Node* GetHead() const { - return head; - } - - void* Allocate() { - Node* ret = head.load(); - - do { - if (ret == nullptr) { - break; - } - } while (!head.compare_exchange_weak(ret, ret->next)); - - return ret; - } - - void Free(void* obj) { - Node* node = static_cast<Node*>(obj); - - Node* cur_head = head.load(); - do { - node->next = cur_head; - } while (!head.compare_exchange_weak(cur_head, node)); - } - -private: - std::atomic<Node*> head{}; - std::size_t obj_size{}; -}; - -} // namespace impl - -class SlabHeapBase : NonCopyable { -public: - constexpr SlabHeapBase() = default; - - constexpr bool Contains(uintptr_t addr) const { - return start <= addr && addr < end; - } - - constexpr std::size_t GetSlabHeapSize() const { - return (end - start) / GetObjectSize(); - } - - constexpr std::size_t GetObjectSize() const { - return impl.GetObjectSize(); - } - - constexpr uintptr_t GetSlabHeapAddress() const { - return start; - } - - std::size_t GetObjectIndexImpl(const void* obj) const { - return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize(); - } - - std::size_t GetPeakIndex() const { - return GetObjectIndexImpl(reinterpret_cast<const void*>(peak)); - } - - void* AllocateImpl() { - return impl.Allocate(); - } - - void FreeImpl(void* obj) { - // Don't allow freeing an object that wasn't allocated from this heap - ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); - impl.Free(obj); - } - - void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { - // Ensure we don't initialize a slab using null memory - ASSERT(memory != nullptr); - - // Initialize the base allocator - impl.Initialize(obj_size); - - // Set our tracking variables - const std::size_t num_obj = (memory_size / obj_size); - start = reinterpret_cast<uintptr_t>(memory); - end = start + num_obj * obj_size; - peak = start; - - // Free the objects - u8* cur = reinterpret_cast<u8*>(end); - - for (std::size_t i{}; i < num_obj; i++) { - cur -= obj_size; - impl.Free(cur); - } - } - -private: - using Impl = impl::SlabHeapImpl; - - Impl impl; - uintptr_t peak{}; - uintptr_t start{}; - uintptr_t end{}; -}; - -template <typename T> -class SlabHeap final : public SlabHeapBase { -public: - constexpr SlabHeap() : SlabHeapBase() {} - - void Initialize(void* memory, std::size_t memory_size) { - InitializeImpl(sizeof(T), memory, memory_size); - } - - T* Allocate() { - T* obj = static_cast<T*>(AllocateImpl()); - if (obj != nullptr) { - new (obj) T(); - } - return obj; - } - - void Free(T* obj) { - FreeImpl(obj); - } - - constexpr std::size_t GetObjectIndex(const T* obj) const { - return GetObjectIndexImpl(obj); - } -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/system_control.cpp b/src/core/hle/kernel/memory/system_control.cpp deleted file mode 100644 index 11d204bc2..000000000 --- a/src/core/hle/kernel/memory/system_control.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <random> - -#include "core/hle/kernel/memory/system_control.h" - -namespace Kernel::Memory::SystemControl { -namespace { -template <typename F> -u64 GenerateUniformRange(u64 min, u64 max, F f) { - // Handle the case where the difference is too large to represent. - if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) { - return f(); - } - - // Iterate until we get a value in range. - const u64 range_size = ((max + 1) - min); - const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size; - while (true) { - if (const u64 rnd = f(); rnd < effective_max) { - return min + (rnd % range_size); - } - } -} - -u64 GenerateRandomU64ForInit() { - static std::random_device device; - static std::mt19937 gen(device()); - static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max()); - return distribution(gen); -} -} // Anonymous namespace - -u64 GenerateRandomRange(u64 min, u64 max) { - return GenerateUniformRange(min, max, GenerateRandomU64ForInit); -} - -} // namespace Kernel::Memory::SystemControl diff --git a/src/core/hle/kernel/memory/system_control.h b/src/core/hle/kernel/memory/system_control.h deleted file mode 100644 index 19cab8cbc..000000000 --- a/src/core/hle/kernel/memory/system_control.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -namespace Kernel::Memory::SystemControl { - -u64 GenerateRandomRange(u64 min, u64 max); - -} // namespace Kernel::Memory::SystemControl |
