2022-04-23 10:59:50 +02:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "common/alignment.h"
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/common_types.h"
|
2022-09-10 06:17:52 +02:00
|
|
|
#include "common/intrusive_red_black_tree.h"
|
2021-02-13 02:02:51 +01:00
|
|
|
#include "core/hle/kernel/memory_types.h"
|
2020-04-05 20:45:58 +02:00
|
|
|
#include "core/hle/kernel/svc_types.h"
|
|
|
|
|
2021-02-13 02:02:51 +01:00
|
|
|
namespace Kernel {
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2021-02-13 02:02:51 +01:00
|
|
|
enum class KMemoryState : u32 {
|
2020-04-05 20:45:58 +02:00
|
|
|
None = 0,
|
2020-04-23 17:37:12 +02:00
|
|
|
Mask = 0xFF,
|
2020-04-05 20:45:58 +02:00
|
|
|
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),
|
2022-10-29 22:59:38 +02:00
|
|
|
FlagLinearMapped = (1 << 26),
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
|
|
|
|
FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical |
|
|
|
|
FlagCanDeviceMap | FlagCanAlignedDeviceMap | FlagCanIpcUserBuffer |
|
2022-10-29 22:59:38 +02:00
|
|
|
FlagReferenceCounted | FlagCanChangeAttribute | FlagLinearMapped,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
FlagsCode = FlagCanDebug | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
|
|
|
|
FlagMapped | FlagCode | FlagCanQueryPhysical | FlagCanDeviceMap |
|
2022-10-29 22:59:38 +02:00
|
|
|
FlagCanAlignedDeviceMap | FlagReferenceCounted | FlagLinearMapped,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-10-29 22:59:38 +02:00
|
|
|
FlagsMisc = FlagMapped | FlagReferenceCounted | FlagCanQueryPhysical | FlagCanDeviceMap |
|
|
|
|
FlagLinearMapped,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
Free = static_cast<u32>(Svc::MemoryState::Free),
|
2022-10-29 22:59:38 +02:00
|
|
|
Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap |
|
|
|
|
FlagCanAlignedDeviceMap,
|
2020-04-05 20:45:58 +02:00
|
|
|
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,
|
|
|
|
Normal = static_cast<u32>(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory,
|
2022-10-29 22:59:38 +02:00
|
|
|
Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted |
|
|
|
|
FlagLinearMapped,
|
|
|
|
|
|
|
|
// Alias was removed after 1.0.0.
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
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,
|
|
|
|
|
2022-10-29 22:59:38 +02:00
|
|
|
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagLinearMapped,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-10-29 22:59:38 +02:00
|
|
|
Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc |
|
2022-01-08 12:13:17 +01:00
|
|
|
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
|
|
|
|
FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-10-29 22:59:38 +02:00
|
|
|
SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc |
|
2022-01-08 12:13:17 +01:00
|
|
|
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
|
2022-10-29 22:59:38 +02:00
|
|
|
FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc |
|
|
|
|
FlagCanUseNonDeviceIpc,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
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 |
|
2022-10-29 22:59:38 +02:00
|
|
|
FlagReferenceCounted | FlagCanDebug | FlagLinearMapped,
|
|
|
|
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted |
|
|
|
|
FlagLinearMapped,
|
2022-01-08 12:13:17 +01:00
|
|
|
|
|
|
|
Coverage = static_cast<u32>(Svc::MemoryState::Coverage) | FlagMapped,
|
2022-10-29 22:59:38 +02:00
|
|
|
|
|
|
|
Insecure = static_cast<u32>(Svc::MemoryState::Insecure) | FlagMapped | FlagReferenceCounted |
|
|
|
|
FlagLinearMapped | FlagCanChangeAttribute | FlagCanDeviceMap |
|
|
|
|
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
2020-04-05 20:45:58 +02:00
|
|
|
};
|
2021-02-13 02:02:51 +01:00
|
|
|
DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
|
|
|
|
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::Free) == 0x00000000);
|
2022-10-29 22:59:38 +02:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::Io) == 0x00182001);
|
2021-02-13 02:02:51 +01:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::Static) == 0x00042002);
|
2022-10-29 22:59:38 +02:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::Code) == 0x04DC7E03);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x07FEBD04);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::Normal) == 0x077EBD05);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::Shared) == 0x04402006);
|
|
|
|
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x04DD7E08);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x07FFBD09);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400200C);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F);
|
2021-02-13 02:02:51 +01:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
|
2022-10-29 22:59:38 +02:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x044C2812);
|
2021-02-13 02:02:51 +01:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
|
2022-10-29 22:59:38 +02:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x04402214);
|
|
|
|
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x04402015);
|
2022-01-08 12:13:17 +01:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016);
|
2022-10-29 22:59:38 +02:00
|
|
|
static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x05583817);
|
2021-02-13 02:02:51 +01:00
|
|
|
|
|
|
|
enum class KMemoryPermission : u8 {
|
2020-04-05 20:45:58 +02:00
|
|
|
None = 0,
|
2021-12-28 09:18:41 +01:00
|
|
|
All = static_cast<u8>(~None),
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2021-12-05 21:04:08 +01:00
|
|
|
KernelShift = 3,
|
|
|
|
|
2022-10-29 22:59:38 +02:00
|
|
|
KernelRead = static_cast<u8>(Svc::MemoryPermission::Read) << KernelShift,
|
|
|
|
KernelWrite = static_cast<u8>(Svc::MemoryPermission::Write) << KernelShift,
|
|
|
|
KernelExecute = static_cast<u8>(Svc::MemoryPermission::Execute) << KernelShift,
|
2021-12-05 21:04:08 +01:00
|
|
|
|
|
|
|
NotMapped = (1 << (2 * KernelShift)),
|
|
|
|
|
|
|
|
KernelReadWrite = KernelRead | KernelWrite,
|
|
|
|
KernelReadExecute = KernelRead | KernelExecute,
|
|
|
|
|
2022-10-29 22:59:38 +02:00
|
|
|
UserRead = static_cast<u8>(Svc::MemoryPermission::Read) | KernelRead,
|
|
|
|
UserWrite = static_cast<u8>(Svc::MemoryPermission::Write) | KernelWrite,
|
|
|
|
UserExecute = static_cast<u8>(Svc::MemoryPermission::Execute),
|
2021-12-05 21:04:08 +01:00
|
|
|
|
|
|
|
UserReadWrite = UserRead | UserWrite,
|
|
|
|
UserReadExecute = UserRead | UserExecute,
|
|
|
|
|
2022-10-29 22:59:38 +02:00
|
|
|
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
|
|
|
|
Svc::MemoryPermission::Execute),
|
|
|
|
|
|
|
|
IpcLockChangeMask = NotMapped | UserReadWrite,
|
2020-04-05 20:45:58 +02:00
|
|
|
};
|
2021-02-13 02:02:51 +01:00
|
|
|
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2021-04-30 23:53:22 +02:00
|
|
|
constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) {
|
2022-01-08 12:13:17 +01:00
|
|
|
return static_cast<KMemoryPermission>(
|
|
|
|
(static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserMask) |
|
|
|
|
KMemoryPermission::KernelRead |
|
|
|
|
((static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserWrite)
|
|
|
|
<< KMemoryPermission::KernelShift) |
|
|
|
|
(perm == Svc::MemoryPermission::None ? KMemoryPermission::NotMapped
|
|
|
|
: KMemoryPermission::None));
|
2021-04-30 23:53:22 +02:00
|
|
|
}
|
|
|
|
|
2021-02-13 02:02:51 +01:00
|
|
|
enum class KMemoryAttribute : u8 {
|
2020-04-05 20:45:58 +02:00
|
|
|
None = 0x00,
|
2022-09-10 06:17:52 +02:00
|
|
|
All = 0xFF,
|
|
|
|
UserMask = All,
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
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),
|
|
|
|
|
2022-01-08 12:13:17 +01:00
|
|
|
SetMask = Uncached,
|
2020-04-05 20:45:58 +02:00
|
|
|
};
|
2021-02-13 02:02:51 +01:00
|
|
|
DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute);
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
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);
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2021-02-13 02:02:51 +01:00
|
|
|
struct KMemoryInfo {
|
2022-09-10 06:17:52 +02:00
|
|
|
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;
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
constexpr Svc::MemoryInfo GetSvcMemoryInfo() const {
|
|
|
|
return {
|
2022-11-03 15:22:05 +01:00
|
|
|
.base_address = m_address,
|
2022-09-10 06:17:52 +02:00
|
|
|
.size = m_size,
|
|
|
|
.state = static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask),
|
2022-11-03 15:22:05 +01:00
|
|
|
.attribute =
|
|
|
|
static_cast<Svc::MemoryAttribute>(m_attribute & KMemoryAttribute::UserMask),
|
|
|
|
.permission =
|
|
|
|
static_cast<Svc::MemoryPermission>(m_permission & KMemoryPermission::UserMask),
|
|
|
|
.ipc_count = m_ipc_lock_count,
|
|
|
|
.device_count = m_device_use_count,
|
2022-09-10 06:17:52 +02:00
|
|
|
.padding = {},
|
2020-04-05 20:45:58 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr uintptr_t GetAddress() const {
|
|
|
|
return m_address;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr size_t GetSize() const {
|
|
|
|
return m_size;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
constexpr size_t GetNumPages() const {
|
|
|
|
return this->GetSize() / PageSize;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
constexpr uintptr_t GetEndAddress() const {
|
|
|
|
return this->GetAddress() + this->GetSize();
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
constexpr uintptr_t GetLastAddress() const {
|
|
|
|
return this->GetEndAddress() - 1;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
constexpr u16 GetIpcLockCount() const {
|
|
|
|
return m_ipc_lock_count;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
constexpr u16 GetIpcDisableMergeCount() const {
|
|
|
|
return m_ipc_disable_merge_count;
|
|
|
|
}
|
|
|
|
|
2022-01-08 12:13:17 +01:00
|
|
|
constexpr KMemoryState GetState() const {
|
2022-09-10 06:17:52 +02:00
|
|
|
return m_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr KMemoryPermission GetPermission() const {
|
|
|
|
return m_permission;
|
2022-01-08 12:13:17 +01:00
|
|
|
}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
constexpr KMemoryPermission GetOriginalPermission() const {
|
|
|
|
return m_original_permission;
|
|
|
|
}
|
|
|
|
|
2022-01-08 12:13:17 +01:00
|
|
|
constexpr KMemoryAttribute GetAttribute() const {
|
2022-09-10 06:17:52 +02:00
|
|
|
return m_attribute;
|
2022-01-08 12:13:17 +01:00
|
|
|
}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const {
|
|
|
|
return m_disable_merge_attribute;
|
2022-01-08 12:13:17 +01:00
|
|
|
}
|
2020-04-05 20:45:58 +02:00
|
|
|
};
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> {
|
2020-04-05 20:45:58 +02:00
|
|
|
private:
|
2022-12-05 21:00:34 +01:00
|
|
|
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{KMemoryState::None};
|
|
|
|
u16 m_ipc_lock_count{};
|
|
|
|
u16 m_device_use_count{};
|
|
|
|
u16 m_ipc_disable_merge_count{};
|
|
|
|
KMemoryPermission m_permission{KMemoryPermission::None};
|
|
|
|
KMemoryPermission m_original_permission{KMemoryPermission::None};
|
|
|
|
KMemoryAttribute m_attribute{KMemoryAttribute::None};
|
|
|
|
KMemoryBlockDisableMergeAttribute m_disable_merge_attribute{
|
|
|
|
KMemoryBlockDisableMergeAttribute::None};
|
2020-04-05 20:45:58 +02:00
|
|
|
|
|
|
|
public:
|
2021-02-13 02:02:51 +01:00
|
|
|
static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) {
|
2020-04-05 20:45:58 +02:00
|
|
|
if (lhs.GetAddress() < rhs.GetAddress()) {
|
|
|
|
return -1;
|
|
|
|
} else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
constexpr VAddr GetAddress() const {
|
2022-09-10 06:17:52 +02:00
|
|
|
return m_address;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr size_t GetNumPages() const {
|
|
|
|
return m_num_pages;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr size_t GetSize() const {
|
|
|
|
return this->GetNumPages() * PageSize;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr VAddr GetEndAddress() const {
|
2022-09-10 06:17:52 +02:00
|
|
|
return this->GetAddress() + this->GetSize();
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr VAddr GetLastAddress() const {
|
2022-09-10 06:17:52 +02:00
|
|
|
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;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2021-02-13 02:02:51 +01:00
|
|
|
constexpr KMemoryInfo GetMemoryInfo() const {
|
2020-04-05 20:45:58 +02:00
|
|
|
return {
|
2022-09-10 06:17:52 +02:00
|
|
|
.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,
|
2020-04-05 20:45:58 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
public:
|
|
|
|
explicit KMemoryBlock() = default;
|
|
|
|
|
|
|
|
constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
|
|
|
|
KMemoryAttribute attr)
|
2022-12-05 21:00:34 +01:00
|
|
|
: Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), m_address(addr), m_num_pages(np),
|
|
|
|
m_memory_state(ms), m_permission(p), m_attribute(attr) {}
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
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;
|
2020-04-23 17:37:12 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
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);
|
2020-04-23 17:37:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
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);
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr void UpdateDeviceDisableMergeStateForShareLeft(
|
|
|
|
[[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission/right aren't used.
|
2022-09-10 06:17:52 +02:00
|
|
|
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);
|
|
|
|
}
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr void UpdateDeviceDisableMergeStateForShareRight(
|
|
|
|
[[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission/left aren't used.
|
2022-09-10 06:17:52 +02:00
|
|
|
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);
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr void ShareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
|
|
|
|
bool right) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission isn't used.
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
// We must either be shared or have a zero lock count.
|
|
|
|
ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared ||
|
|
|
|
m_device_use_count == 0);
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
// 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);
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(
|
|
|
|
[[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission/right aren't used.
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
if (left) {
|
|
|
|
if (!m_device_disable_merge_left_count) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
--m_device_disable_merge_left_count;
|
|
|
|
}
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
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);
|
|
|
|
}
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr void UpdateDeviceDisableMergeStateForUnshareRight(
|
|
|
|
[[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission/left aren't used.
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr void UpdateDeviceDisableMergeStateForUnshare(KMemoryPermission new_perm, bool left,
|
|
|
|
bool right) {
|
|
|
|
this->UpdateDeviceDisableMergeStateForUnshareLeft(new_perm, left, right);
|
|
|
|
this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right);
|
|
|
|
}
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr void UnshareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
|
|
|
|
bool right) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission isn't used.
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
// 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) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission isn't used.
|
2022-09-10 06:17:52 +02:00
|
|
|
|
|
|
|
// 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) {
|
2022-10-29 22:59:38 +02:00
|
|
|
// New permission isn't used.
|
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2022-09-10 06:17:52 +02:00
|
|
|
constexpr KMemoryBlockDisableMergeAttribute GetDisableMergeAttribute() const {
|
|
|
|
return m_disable_merge_attribute;
|
2020-04-05 20:45:58 +02:00
|
|
|
}
|
|
|
|
};
|
2021-02-13 02:02:51 +01:00
|
|
|
static_assert(std::is_trivially_destructible<KMemoryBlock>::value);
|
2020-04-05 20:45:58 +02:00
|
|
|
|
2021-02-13 02:02:51 +01:00
|
|
|
} // namespace Kernel
|