|
|
@@ -6,6 +6,7 @@
|
|
|
#include "common/alignment.h"
|
|
|
#include "common/assert.h"
|
|
|
#include "common/common_types.h"
|
|
|
+#include "common/intrusive_red_black_tree.h"
|
|
|
#include "core/hle/kernel/memory_types.h"
|
|
|
#include "core/hle/kernel/svc_types.h"
|
|
|
|
|
|
@@ -168,9 +169,8 @@ constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission per
|
|
|
|
|
|
enum class KMemoryAttribute : u8 {
|
|
|
None = 0x00,
|
|
|
- Mask = 0x7F,
|
|
|
- All = Mask,
|
|
|
- DontCareMask = 0x80,
|
|
|
+ All = 0xFF,
|
|
|
+ UserMask = All,
|
|
|
|
|
|
Locked = static_cast<u8>(Svc::MemoryAttribute::Locked),
|
|
|
IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked),
|
|
|
@@ -178,76 +178,112 @@ enum class KMemoryAttribute : u8 {
|
|
|
Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
|
|
|
|
|
|
SetMask = Uncached,
|
|
|
-
|
|
|
- IpcAndDeviceMapped = IpcLocked | DeviceShared,
|
|
|
- LockedAndIpcLocked = Locked | IpcLocked,
|
|
|
- DeviceSharedAndUncached = DeviceShared | Uncached
|
|
|
};
|
|
|
DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute);
|
|
|
|
|
|
-static_assert((static_cast<u8>(KMemoryAttribute::Mask) &
|
|
|
- static_cast<u8>(KMemoryAttribute::DontCareMask)) == 0);
|
|
|
+enum class KMemoryBlockDisableMergeAttribute : u8 {
|
|
|
+ None = 0,
|
|
|
+ Normal = (1u << 0),
|
|
|
+ DeviceLeft = (1u << 1),
|
|
|
+ IpcLeft = (1u << 2),
|
|
|
+ Locked = (1u << 3),
|
|
|
+ DeviceRight = (1u << 4),
|
|
|
+
|
|
|
+ AllLeft = Normal | DeviceLeft | IpcLeft | Locked,
|
|
|
+ AllRight = DeviceRight,
|
|
|
+};
|
|
|
+DECLARE_ENUM_FLAG_OPERATORS(KMemoryBlockDisableMergeAttribute);
|
|
|
|
|
|
struct KMemoryInfo {
|
|
|
- VAddr addr{};
|
|
|
- std::size_t size{};
|
|
|
- KMemoryState state{};
|
|
|
- KMemoryPermission perm{};
|
|
|
- KMemoryAttribute attribute{};
|
|
|
- KMemoryPermission original_perm{};
|
|
|
- u16 ipc_lock_count{};
|
|
|
- u16 device_use_count{};
|
|
|
+ uintptr_t m_address;
|
|
|
+ size_t m_size;
|
|
|
+ KMemoryState m_state;
|
|
|
+ u16 m_device_disable_merge_left_count;
|
|
|
+ u16 m_device_disable_merge_right_count;
|
|
|
+ u16 m_ipc_lock_count;
|
|
|
+ u16 m_device_use_count;
|
|
|
+ u16 m_ipc_disable_merge_count;
|
|
|
+ KMemoryPermission m_permission;
|
|
|
+ KMemoryAttribute m_attribute;
|
|
|
+ KMemoryPermission m_original_permission;
|
|
|
+ KMemoryBlockDisableMergeAttribute m_disable_merge_attribute;
|
|
|
|
|
|
constexpr Svc::MemoryInfo GetSvcMemoryInfo() const {
|
|
|
return {
|
|
|
- addr,
|
|
|
- size,
|
|
|
- static_cast<Svc::MemoryState>(state & KMemoryState::Mask),
|
|
|
- static_cast<Svc::MemoryAttribute>(attribute & KMemoryAttribute::Mask),
|
|
|
- static_cast<Svc::MemoryPermission>(perm & KMemoryPermission::UserMask),
|
|
|
- ipc_lock_count,
|
|
|
- device_use_count,
|
|
|
+ .addr = m_address,
|
|
|
+ .size = m_size,
|
|
|
+ .state = static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask),
|
|
|
+ .attr = static_cast<Svc::MemoryAttribute>(m_attribute & KMemoryAttribute::UserMask),
|
|
|
+ .perm = static_cast<Svc::MemoryPermission>(m_permission & KMemoryPermission::UserMask),
|
|
|
+ .ipc_refcount = m_ipc_lock_count,
|
|
|
+ .device_refcount = m_device_use_count,
|
|
|
+ .padding = {},
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- constexpr VAddr GetAddress() const {
|
|
|
- return addr;
|
|
|
+ constexpr uintptr_t GetAddress() const {
|
|
|
+ return m_address;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr size_t GetSize() const {
|
|
|
+ return m_size;
|
|
|
}
|
|
|
- constexpr std::size_t GetSize() const {
|
|
|
- return size;
|
|
|
+
|
|
|
+ constexpr size_t GetNumPages() const {
|
|
|
+ return this->GetSize() / PageSize;
|
|
|
}
|
|
|
- constexpr std::size_t GetNumPages() const {
|
|
|
- return GetSize() / PageSize;
|
|
|
+
|
|
|
+ constexpr uintptr_t GetEndAddress() const {
|
|
|
+ return this->GetAddress() + this->GetSize();
|
|
|
}
|
|
|
- constexpr VAddr GetEndAddress() const {
|
|
|
- return GetAddress() + GetSize();
|
|
|
+
|
|
|
+ constexpr uintptr_t GetLastAddress() const {
|
|
|
+ return this->GetEndAddress() - 1;
|
|
|
}
|
|
|
- constexpr VAddr GetLastAddress() const {
|
|
|
- return GetEndAddress() - 1;
|
|
|
+
|
|
|
+ constexpr u16 GetIpcLockCount() const {
|
|
|
+ return m_ipc_lock_count;
|
|
|
}
|
|
|
+
|
|
|
+ constexpr u16 GetIpcDisableMergeCount() const {
|
|
|
+ return m_ipc_disable_merge_count;
|
|
|
+ }
|
|
|
+
|
|
|
constexpr KMemoryState GetState() const {
|
|
|
- return state;
|
|
|
+ return m_state;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr KMemoryPermission GetPermission() const {
|
|
|
+ return m_permission;
|
|
|
}
|
|
|
+
|
|
|
+ constexpr KMemoryPermission GetOriginalPermission() const {
|
|
|
+ return m_original_permission;
|
|
|
+ }
|
|
|
+
|
|
|
constexpr KMemoryAttribute GetAttribute() const {
|
|
|
- return attribute;
|
|
|
+ return m_attribute;
|
|
|
}
|
|
|
- constexpr KMemoryPermission GetPermission() const {
|
|
|
- return perm;
|
|
|
+
|
|
|
+ constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const {
|
|
|
+ return m_disable_merge_attribute;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-class KMemoryBlock final {
|
|
|
- friend class KMemoryBlockManager;
|
|
|
-
|
|
|
+class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> {
|
|
|
private:
|
|
|
- VAddr addr{};
|
|
|
- std::size_t num_pages{};
|
|
|
- KMemoryState state{KMemoryState::None};
|
|
|
- u16 ipc_lock_count{};
|
|
|
- u16 device_use_count{};
|
|
|
- KMemoryPermission perm{KMemoryPermission::None};
|
|
|
- KMemoryPermission original_perm{KMemoryPermission::None};
|
|
|
- KMemoryAttribute attribute{KMemoryAttribute::None};
|
|
|
+ u16 m_device_disable_merge_left_count;
|
|
|
+ u16 m_device_disable_merge_right_count;
|
|
|
+ VAddr m_address;
|
|
|
+ size_t m_num_pages;
|
|
|
+ KMemoryState m_memory_state;
|
|
|
+ u16 m_ipc_lock_count;
|
|
|
+ u16 m_device_use_count;
|
|
|
+ u16 m_ipc_disable_merge_count;
|
|
|
+ KMemoryPermission m_permission;
|
|
|
+ KMemoryPermission m_original_permission;
|
|
|
+ KMemoryAttribute m_attribute;
|
|
|
+ KMemoryBlockDisableMergeAttribute m_disable_merge_attribute;
|
|
|
|
|
|
public:
|
|
|
static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) {
|
|
|
@@ -261,113 +297,349 @@ public:
|
|
|
}
|
|
|
|
|
|
public:
|
|
|
- constexpr KMemoryBlock() = default;
|
|
|
- constexpr KMemoryBlock(VAddr addr_, std::size_t num_pages_, KMemoryState state_,
|
|
|
- KMemoryPermission perm_, KMemoryAttribute attribute_)
|
|
|
- : addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {}
|
|
|
-
|
|
|
constexpr VAddr GetAddress() const {
|
|
|
- return addr;
|
|
|
+ return m_address;
|
|
|
}
|
|
|
|
|
|
- constexpr std::size_t GetNumPages() const {
|
|
|
- return num_pages;
|
|
|
+ constexpr size_t GetNumPages() const {
|
|
|
+ return m_num_pages;
|
|
|
}
|
|
|
|
|
|
- constexpr std::size_t GetSize() const {
|
|
|
- return GetNumPages() * PageSize;
|
|
|
+ constexpr size_t GetSize() const {
|
|
|
+ return this->GetNumPages() * PageSize;
|
|
|
}
|
|
|
|
|
|
constexpr VAddr GetEndAddress() const {
|
|
|
- return GetAddress() + GetSize();
|
|
|
+ return this->GetAddress() + this->GetSize();
|
|
|
}
|
|
|
|
|
|
constexpr VAddr GetLastAddress() const {
|
|
|
- return GetEndAddress() - 1;
|
|
|
+ return this->GetEndAddress() - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr u16 GetIpcLockCount() const {
|
|
|
+ return m_ipc_lock_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr u16 GetIpcDisableMergeCount() const {
|
|
|
+ return m_ipc_disable_merge_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr KMemoryPermission GetPermission() const {
|
|
|
+ return m_permission;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr KMemoryPermission GetOriginalPermission() const {
|
|
|
+ return m_original_permission;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr KMemoryAttribute GetAttribute() const {
|
|
|
+ return m_attribute;
|
|
|
}
|
|
|
|
|
|
constexpr KMemoryInfo GetMemoryInfo() const {
|
|
|
return {
|
|
|
- GetAddress(), GetSize(), state, perm,
|
|
|
- attribute, original_perm, ipc_lock_count, device_use_count,
|
|
|
+ .m_address = this->GetAddress(),
|
|
|
+ .m_size = this->GetSize(),
|
|
|
+ .m_state = m_memory_state,
|
|
|
+ .m_device_disable_merge_left_count = m_device_disable_merge_left_count,
|
|
|
+ .m_device_disable_merge_right_count = m_device_disable_merge_right_count,
|
|
|
+ .m_ipc_lock_count = m_ipc_lock_count,
|
|
|
+ .m_device_use_count = m_device_use_count,
|
|
|
+ .m_ipc_disable_merge_count = m_ipc_disable_merge_count,
|
|
|
+ .m_permission = m_permission,
|
|
|
+ .m_attribute = m_attribute,
|
|
|
+ .m_original_permission = m_original_permission,
|
|
|
+ .m_disable_merge_attribute = m_disable_merge_attribute,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
- void ShareToDevice(KMemoryPermission /*new_perm*/) {
|
|
|
- ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared ||
|
|
|
- device_use_count == 0);
|
|
|
- attribute |= KMemoryAttribute::DeviceShared;
|
|
|
- const u16 new_use_count{++device_use_count};
|
|
|
- ASSERT(new_use_count > 0);
|
|
|
+public:
|
|
|
+ explicit KMemoryBlock() = default;
|
|
|
+
|
|
|
+ constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
|
|
|
+ KMemoryAttribute attr)
|
|
|
+ : Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(),
|
|
|
+ m_device_disable_merge_left_count(), m_device_disable_merge_right_count(),
|
|
|
+ m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0),
|
|
|
+ m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p),
|
|
|
+ m_original_permission(KMemoryPermission::None), m_attribute(attr),
|
|
|
+ m_disable_merge_attribute() {}
|
|
|
+
|
|
|
+ constexpr void Initialize(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
|
|
|
+ KMemoryAttribute attr) {
|
|
|
+ m_device_disable_merge_left_count = 0;
|
|
|
+ m_device_disable_merge_right_count = 0;
|
|
|
+ m_address = addr;
|
|
|
+ m_num_pages = np;
|
|
|
+ m_memory_state = ms;
|
|
|
+ m_ipc_lock_count = 0;
|
|
|
+ m_device_use_count = 0;
|
|
|
+ m_permission = p;
|
|
|
+ m_original_permission = KMemoryPermission::None;
|
|
|
+ m_attribute = attr;
|
|
|
+ m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute::None;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const {
|
|
|
+ constexpr auto AttributeIgnoreMask =
|
|
|
+ KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared;
|
|
|
+ return m_memory_state == s && m_permission == p &&
|
|
|
+ (m_attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask);
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr bool HasSameProperties(const KMemoryBlock& rhs) const {
|
|
|
+ return m_memory_state == rhs.m_memory_state && m_permission == rhs.m_permission &&
|
|
|
+ m_original_permission == rhs.m_original_permission &&
|
|
|
+ m_attribute == rhs.m_attribute && m_ipc_lock_count == rhs.m_ipc_lock_count &&
|
|
|
+ m_device_use_count == rhs.m_device_use_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr bool CanMergeWith(const KMemoryBlock& rhs) const {
|
|
|
+ return this->HasSameProperties(rhs) &&
|
|
|
+ (m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllRight) ==
|
|
|
+ KMemoryBlockDisableMergeAttribute::None &&
|
|
|
+ (rhs.m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllLeft) ==
|
|
|
+ KMemoryBlockDisableMergeAttribute::None;
|
|
|
}
|
|
|
|
|
|
- void UnshareToDevice(KMemoryPermission /*new_perm*/) {
|
|
|
- ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared);
|
|
|
- const u16 prev_use_count{device_use_count--};
|
|
|
- ASSERT(prev_use_count > 0);
|
|
|
- if (prev_use_count == 1) {
|
|
|
- attribute &= ~KMemoryAttribute::DeviceShared;
|
|
|
+ constexpr bool Contains(VAddr addr) const {
|
|
|
+ return this->GetAddress() <= addr && addr <= this->GetEndAddress();
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr void Add(const KMemoryBlock& added_block) {
|
|
|
+ ASSERT(added_block.GetNumPages() > 0);
|
|
|
+ ASSERT(this->GetAddress() + added_block.GetSize() - 1 <
|
|
|
+ this->GetEndAddress() + added_block.GetSize() - 1);
|
|
|
+
|
|
|
+ m_num_pages += added_block.GetNumPages();
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute | added_block.m_disable_merge_attribute);
|
|
|
+ m_device_disable_merge_right_count = added_block.m_device_disable_merge_right_count;
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr void Update(KMemoryState s, KMemoryPermission p, KMemoryAttribute a,
|
|
|
+ bool set_disable_merge_attr, u8 set_mask, u8 clear_mask) {
|
|
|
+ ASSERT(m_original_permission == KMemoryPermission::None);
|
|
|
+ ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::None);
|
|
|
+
|
|
|
+ m_memory_state = s;
|
|
|
+ m_permission = p;
|
|
|
+ m_attribute = static_cast<KMemoryAttribute>(
|
|
|
+ a | (m_attribute & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)));
|
|
|
+
|
|
|
+ if (set_disable_merge_attr && set_mask != 0) {
|
|
|
+ m_disable_merge_attribute = m_disable_merge_attribute |
|
|
|
+ static_cast<KMemoryBlockDisableMergeAttribute>(set_mask);
|
|
|
+ }
|
|
|
+ if (clear_mask != 0) {
|
|
|
+ m_disable_merge_attribute = m_disable_merge_attribute &
|
|
|
+ static_cast<KMemoryBlockDisableMergeAttribute>(~clear_mask);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-private:
|
|
|
- constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const {
|
|
|
- constexpr KMemoryAttribute AttributeIgnoreMask{KMemoryAttribute::DontCareMask |
|
|
|
- KMemoryAttribute::IpcLocked |
|
|
|
- KMemoryAttribute::DeviceShared};
|
|
|
- return state == s && perm == p &&
|
|
|
- (attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask);
|
|
|
+ constexpr void Split(KMemoryBlock* block, VAddr addr) {
|
|
|
+ ASSERT(this->GetAddress() < addr);
|
|
|
+ ASSERT(this->Contains(addr));
|
|
|
+ ASSERT(Common::IsAligned(addr, PageSize));
|
|
|
+
|
|
|
+ block->m_address = m_address;
|
|
|
+ block->m_num_pages = (addr - this->GetAddress()) / PageSize;
|
|
|
+ block->m_memory_state = m_memory_state;
|
|
|
+ block->m_ipc_lock_count = m_ipc_lock_count;
|
|
|
+ block->m_device_use_count = m_device_use_count;
|
|
|
+ block->m_permission = m_permission;
|
|
|
+ block->m_original_permission = m_original_permission;
|
|
|
+ block->m_attribute = m_attribute;
|
|
|
+ block->m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllLeft);
|
|
|
+ block->m_ipc_disable_merge_count = m_ipc_disable_merge_count;
|
|
|
+ block->m_device_disable_merge_left_count = m_device_disable_merge_left_count;
|
|
|
+ block->m_device_disable_merge_right_count = 0;
|
|
|
+
|
|
|
+ m_address = addr;
|
|
|
+ m_num_pages -= block->m_num_pages;
|
|
|
+
|
|
|
+ m_ipc_disable_merge_count = 0;
|
|
|
+ m_device_disable_merge_left_count = 0;
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllRight);
|
|
|
}
|
|
|
|
|
|
- constexpr bool HasSameProperties(const KMemoryBlock& 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 void UpdateDeviceDisableMergeStateForShareLeft(
|
|
|
+ [[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
|
|
|
+ if (left) {
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::DeviceLeft);
|
|
|
+ const u16 new_device_disable_merge_left_count = ++m_device_disable_merge_left_count;
|
|
|
+ ASSERT(new_device_disable_merge_left_count > 0);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- constexpr bool Contains(VAddr start) const {
|
|
|
- return GetAddress() <= start && start <= GetEndAddress();
|
|
|
+ constexpr void UpdateDeviceDisableMergeStateForShareRight(
|
|
|
+ [[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
|
|
|
+ if (right) {
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::DeviceRight);
|
|
|
+ const u16 new_device_disable_merge_right_count = ++m_device_disable_merge_right_count;
|
|
|
+ ASSERT(new_device_disable_merge_right_count > 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr void UpdateDeviceDisableMergeStateForShare(KMemoryPermission new_perm, bool left,
|
|
|
+ bool right) {
|
|
|
+ this->UpdateDeviceDisableMergeStateForShareLeft(new_perm, left, right);
|
|
|
+ this->UpdateDeviceDisableMergeStateForShareRight(new_perm, left, right);
|
|
|
}
|
|
|
|
|
|
- constexpr void Add(std::size_t count) {
|
|
|
- ASSERT(count > 0);
|
|
|
- ASSERT(GetAddress() + count * PageSize - 1 < GetEndAddress() + count * PageSize - 1);
|
|
|
+ constexpr void ShareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
|
|
|
+ bool right) {
|
|
|
+ // We must either be shared or have a zero lock count.
|
|
|
+ ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared ||
|
|
|
+ m_device_use_count == 0);
|
|
|
|
|
|
- num_pages += count;
|
|
|
+ // Share.
|
|
|
+ const u16 new_count = ++m_device_use_count;
|
|
|
+ ASSERT(new_count > 0);
|
|
|
+
|
|
|
+ m_attribute = static_cast<KMemoryAttribute>(m_attribute | KMemoryAttribute::DeviceShared);
|
|
|
+
|
|
|
+ this->UpdateDeviceDisableMergeStateForShare(new_perm, left, right);
|
|
|
}
|
|
|
|
|
|
- constexpr void Update(KMemoryState new_state, KMemoryPermission new_perm,
|
|
|
- KMemoryAttribute new_attribute) {
|
|
|
- ASSERT(original_perm == KMemoryPermission::None);
|
|
|
- ASSERT((attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::None);
|
|
|
+ constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(
|
|
|
+ [[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
|
|
|
|
|
|
- state = new_state;
|
|
|
- perm = new_perm;
|
|
|
+ if (left) {
|
|
|
+ if (!m_device_disable_merge_left_count) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ --m_device_disable_merge_left_count;
|
|
|
+ }
|
|
|
|
|
|
- attribute = static_cast<KMemoryAttribute>(
|
|
|
- new_attribute |
|
|
|
- (attribute & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)));
|
|
|
+ m_device_disable_merge_left_count =
|
|
|
+ std::min(m_device_disable_merge_left_count, m_device_use_count);
|
|
|
+
|
|
|
+ if (m_device_disable_merge_left_count == 0) {
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute::DeviceLeft);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- constexpr KMemoryBlock Split(VAddr split_addr) {
|
|
|
- ASSERT(GetAddress() < split_addr);
|
|
|
- ASSERT(Contains(split_addr));
|
|
|
- ASSERT(Common::IsAligned(split_addr, PageSize));
|
|
|
+ constexpr void UpdateDeviceDisableMergeStateForUnshareRight(
|
|
|
+ [[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
|
|
|
+ if (right) {
|
|
|
+ const u16 old_device_disable_merge_right_count = m_device_disable_merge_right_count--;
|
|
|
+ ASSERT(old_device_disable_merge_right_count > 0);
|
|
|
+ if (old_device_disable_merge_right_count == 1) {
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute::DeviceRight);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- KMemoryBlock 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;
|
|
|
+ constexpr void UpdateDeviceDisableMergeStateForUnshare(KMemoryPermission new_perm, bool left,
|
|
|
+ bool right) {
|
|
|
+ this->UpdateDeviceDisableMergeStateForUnshareLeft(new_perm, left, right);
|
|
|
+ this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right);
|
|
|
+ }
|
|
|
|
|
|
- addr = split_addr;
|
|
|
- num_pages -= block.num_pages;
|
|
|
+ constexpr void UnshareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
|
|
|
+ bool right) {
|
|
|
+ // We must be shared.
|
|
|
+ ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared);
|
|
|
+
|
|
|
+ // Unhare.
|
|
|
+ const u16 old_count = m_device_use_count--;
|
|
|
+ ASSERT(old_count > 0);
|
|
|
+
|
|
|
+ if (old_count == 1) {
|
|
|
+ m_attribute =
|
|
|
+ static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute::DeviceShared);
|
|
|
+ }
|
|
|
+
|
|
|
+ this->UpdateDeviceDisableMergeStateForUnshare(new_perm, left, right);
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr void UnshareToDeviceRight([[maybe_unused]] KMemoryPermission new_perm, bool left,
|
|
|
+ bool right) {
|
|
|
+
|
|
|
+ // We must be shared.
|
|
|
+ ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared);
|
|
|
+
|
|
|
+ // Unhare.
|
|
|
+ const u16 old_count = m_device_use_count--;
|
|
|
+ ASSERT(old_count > 0);
|
|
|
+
|
|
|
+ if (old_count == 1) {
|
|
|
+ m_attribute =
|
|
|
+ static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute::DeviceShared);
|
|
|
+ }
|
|
|
+
|
|
|
+ this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right);
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr void LockForIpc(KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
|
|
|
+ // We must either be locked or have a zero lock count.
|
|
|
+ ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::IpcLocked ||
|
|
|
+ m_ipc_lock_count == 0);
|
|
|
+
|
|
|
+ // Lock.
|
|
|
+ const u16 new_lock_count = ++m_ipc_lock_count;
|
|
|
+ ASSERT(new_lock_count > 0);
|
|
|
+
|
|
|
+ // If this is our first lock, update our permissions.
|
|
|
+ if (new_lock_count == 1) {
|
|
|
+ ASSERT(m_original_permission == KMemoryPermission::None);
|
|
|
+ ASSERT((m_permission | new_perm | KMemoryPermission::NotMapped) ==
|
|
|
+ (m_permission | KMemoryPermission::NotMapped));
|
|
|
+ ASSERT((m_permission & KMemoryPermission::UserExecute) !=
|
|
|
+ KMemoryPermission::UserExecute ||
|
|
|
+ (new_perm == KMemoryPermission::UserRead));
|
|
|
+ m_original_permission = m_permission;
|
|
|
+ m_permission = static_cast<KMemoryPermission>(
|
|
|
+ (new_perm & KMemoryPermission::IpcLockChangeMask) |
|
|
|
+ (m_original_permission & ~KMemoryPermission::IpcLockChangeMask));
|
|
|
+ }
|
|
|
+ m_attribute = static_cast<KMemoryAttribute>(m_attribute | KMemoryAttribute::IpcLocked);
|
|
|
+
|
|
|
+ if (left) {
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::IpcLeft);
|
|
|
+ const u16 new_ipc_disable_merge_count = ++m_ipc_disable_merge_count;
|
|
|
+ ASSERT(new_ipc_disable_merge_count > 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ constexpr void UnlockForIpc([[maybe_unused]] KMemoryPermission new_perm, bool left,
|
|
|
+ [[maybe_unused]] bool right) {
|
|
|
+ // We must be locked.
|
|
|
+ ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::IpcLocked);
|
|
|
+
|
|
|
+ // Unlock.
|
|
|
+ const u16 old_lock_count = m_ipc_lock_count--;
|
|
|
+ ASSERT(old_lock_count > 0);
|
|
|
+
|
|
|
+ // If this is our last unlock, update our permissions.
|
|
|
+ if (old_lock_count == 1) {
|
|
|
+ ASSERT(m_original_permission != KMemoryPermission::None);
|
|
|
+ m_permission = m_original_permission;
|
|
|
+ m_original_permission = KMemoryPermission::None;
|
|
|
+ m_attribute = static_cast<KMemoryAttribute>(m_attribute & ~KMemoryAttribute::IpcLocked);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (left) {
|
|
|
+ const u16 old_ipc_disable_merge_count = m_ipc_disable_merge_count--;
|
|
|
+ ASSERT(old_ipc_disable_merge_count > 0);
|
|
|
+ if (old_ipc_disable_merge_count == 1) {
|
|
|
+ m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
|
|
|
+ m_disable_merge_attribute & ~KMemoryBlockDisableMergeAttribute::IpcLeft);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return block;
|
|
|
+ constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const {
|
|
|
+ return m_disable_merge_attribute;
|
|
|
}
|
|
|
};
|
|
|
static_assert(std::is_trivially_destructible<KMemoryBlock>::value);
|