core: hle: kernel: k_page_table: Update CheckMemoryState.
This commit is contained in:
parent
26f4e92c1f
commit
b9a313057e
4 changed files with 184 additions and 134 deletions
|
@ -70,11 +70,11 @@ enum class KMemoryState : u32 {
|
||||||
ThreadLocal =
|
ThreadLocal =
|
||||||
static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted,
|
static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted,
|
||||||
|
|
||||||
Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
|
Transfered = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
|
||||||
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
|
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
|
||||||
FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
||||||
|
|
||||||
SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
|
SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
|
||||||
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
|
||||||
|
|
||||||
SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
|
SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
|
||||||
|
@ -93,6 +93,8 @@ enum class KMemoryState : u32 {
|
||||||
GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped |
|
GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped |
|
||||||
FlagReferenceCounted | FlagCanDebug,
|
FlagReferenceCounted | FlagCanDebug,
|
||||||
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted,
|
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted,
|
||||||
|
|
||||||
|
Coverage = static_cast<u32>(Svc::MemoryState::Coverage) | FlagMapped,
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
|
DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
|
||||||
|
|
||||||
|
@ -108,8 +110,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x03FFBD09);
|
||||||
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A);
|
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A);
|
||||||
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B);
|
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B);
|
||||||
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C);
|
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C);
|
||||||
static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x015C3C0D);
|
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x015C3C0D);
|
||||||
static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x005C380E);
|
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x005C380E);
|
||||||
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F);
|
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F);
|
||||||
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
|
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
|
||||||
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811);
|
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811);
|
||||||
|
@ -117,6 +119,7 @@ static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x004C2812);
|
||||||
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
|
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
|
||||||
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214);
|
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214);
|
||||||
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
|
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
|
||||||
|
static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016);
|
||||||
|
|
||||||
enum class KMemoryPermission : u8 {
|
enum class KMemoryPermission : u8 {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
@ -155,7 +158,13 @@ enum class KMemoryPermission : u8 {
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
|
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
|
||||||
|
|
||||||
constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) {
|
constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) {
|
||||||
return static_cast<KMemoryPermission>(perm);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class KMemoryAttribute : u8 {
|
enum class KMemoryAttribute : u8 {
|
||||||
|
@ -169,6 +178,8 @@ enum class KMemoryAttribute : u8 {
|
||||||
DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared),
|
DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared),
|
||||||
Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
|
Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
|
||||||
|
|
||||||
|
SetMask = Uncached,
|
||||||
|
|
||||||
IpcAndDeviceMapped = IpcLocked | DeviceShared,
|
IpcAndDeviceMapped = IpcLocked | DeviceShared,
|
||||||
LockedAndIpcLocked = Locked | IpcLocked,
|
LockedAndIpcLocked = Locked | IpcLocked,
|
||||||
DeviceSharedAndUncached = DeviceShared | Uncached
|
DeviceSharedAndUncached = DeviceShared | Uncached
|
||||||
|
@ -215,6 +226,15 @@ struct KMemoryInfo {
|
||||||
constexpr VAddr GetLastAddress() const {
|
constexpr VAddr GetLastAddress() const {
|
||||||
return GetEndAddress() - 1;
|
return GetEndAddress() - 1;
|
||||||
}
|
}
|
||||||
|
constexpr KMemoryState GetState() const {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
constexpr KMemoryAttribute GetAttribute() const {
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
constexpr KMemoryPermission GetPermission() const {
|
||||||
|
return perm;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class KMemoryBlock final {
|
class KMemoryBlock final {
|
||||||
|
|
|
@ -305,8 +305,8 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:
|
||||||
|
|
||||||
KMemoryState state{};
|
KMemoryState state{};
|
||||||
KMemoryPermission perm{};
|
KMemoryPermission perm{};
|
||||||
CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All,
|
CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size,
|
||||||
KMemoryState::Normal, KMemoryPermission::All,
|
KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All,
|
||||||
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask,
|
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask,
|
||||||
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
||||||
|
|
||||||
|
@ -344,14 +344,14 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st
|
||||||
|
|
||||||
const std::size_t num_pages{size / PageSize};
|
const std::size_t num_pages{size / PageSize};
|
||||||
|
|
||||||
CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, KMemoryState::All,
|
CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, nullptr, src_addr, size,
|
||||||
KMemoryState::Normal, KMemoryPermission::None,
|
KMemoryState::All, KMemoryState::Normal, KMemoryPermission::None,
|
||||||
KMemoryPermission::None, KMemoryAttribute::Mask,
|
KMemoryPermission::None, KMemoryAttribute::Mask,
|
||||||
KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
|
KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
|
||||||
|
|
||||||
KMemoryState state{};
|
KMemoryState state{};
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
&state, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias,
|
&state, nullptr, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias,
|
||||||
KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
|
KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
|
||||||
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
||||||
CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None,
|
CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None,
|
||||||
|
@ -553,7 +553,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||||
|
|
||||||
KMemoryState src_state{};
|
KMemoryState src_state{};
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
&src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
|
&src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
|
||||||
KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite,
|
KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite,
|
||||||
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
||||||
|
|
||||||
|
@ -592,13 +592,13 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
|
||||||
|
|
||||||
KMemoryState src_state{};
|
KMemoryState src_state{};
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
&src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
|
&src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
|
||||||
KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None,
|
KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None,
|
||||||
KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
|
KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
|
||||||
|
|
||||||
KMemoryPermission dst_perm{};
|
KMemoryPermission dst_perm{};
|
||||||
CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, KMemoryState::All,
|
CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, nullptr, dst_addr, size,
|
||||||
KMemoryState::Stack, KMemoryPermission::None,
|
KMemoryState::All, KMemoryState::Stack, KMemoryPermission::None,
|
||||||
KMemoryPermission::None, KMemoryAttribute::Mask,
|
KMemoryPermission::None, KMemoryAttribute::Mask,
|
||||||
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
||||||
|
|
||||||
|
@ -721,7 +721,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
|
||||||
KMemoryPermission prev_perm{};
|
KMemoryPermission prev_perm{};
|
||||||
|
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
&prev_state, &prev_perm, nullptr, addr, size, KMemoryState::FlagCode,
|
&prev_state, &prev_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCode,
|
||||||
KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None,
|
KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None,
|
||||||
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
|
||||||
|
|
||||||
|
@ -782,7 +782,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
|
||||||
KMemoryAttribute attribute{};
|
KMemoryAttribute attribute{};
|
||||||
|
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
&state, nullptr, &attribute, addr, size,
|
&state, nullptr, &attribute, nullptr, addr, size,
|
||||||
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
|
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
|
||||||
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All,
|
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All,
|
||||||
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None,
|
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None,
|
||||||
|
@ -799,7 +799,7 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||||
KMemoryState state{};
|
KMemoryState state{};
|
||||||
|
|
||||||
CASCADE_CODE(
|
CASCADE_CODE(
|
||||||
CheckMemoryState(&state, nullptr, nullptr, addr, size,
|
CheckMemoryState(&state, nullptr, nullptr, nullptr, addr, size,
|
||||||
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
|
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
|
||||||
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
|
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
|
||||||
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
|
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
|
||||||
|
@ -820,7 +820,7 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
|
||||||
KMemoryState old_state;
|
KMemoryState old_state;
|
||||||
KMemoryPermission old_perm;
|
KMemoryPermission old_perm;
|
||||||
R_TRY(this->CheckMemoryState(
|
R_TRY(this->CheckMemoryState(
|
||||||
std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size,
|
std::addressof(old_state), std::addressof(old_perm), nullptr, nullptr, addr, size,
|
||||||
KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None,
|
KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None,
|
||||||
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
|
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
|
||||||
|
|
||||||
|
@ -846,7 +846,7 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryA
|
||||||
KMemoryAttribute attribute{};
|
KMemoryAttribute attribute{};
|
||||||
|
|
||||||
CASCADE_CODE(CheckMemoryState(
|
CASCADE_CODE(CheckMemoryState(
|
||||||
&state, &perm, &attribute, addr, size, KMemoryState::FlagCanChangeAttribute,
|
&state, &perm, &attribute, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
|
||||||
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
||||||
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
||||||
KMemoryAttribute::DeviceSharedAndUncached));
|
KMemoryAttribute::DeviceSharedAndUncached));
|
||||||
|
@ -1019,7 +1019,7 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||||
|
|
||||||
KMemoryPermission perm{};
|
KMemoryPermission perm{};
|
||||||
if (const ResultCode result{CheckMemoryState(
|
if (const ResultCode result{CheckMemoryState(
|
||||||
nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
|
nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
|
||||||
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
||||||
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
||||||
KMemoryAttribute::DeviceSharedAndUncached)};
|
KMemoryAttribute::DeviceSharedAndUncached)};
|
||||||
|
@ -1042,7 +1042,7 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||||
|
|
||||||
KMemoryPermission perm{};
|
KMemoryPermission perm{};
|
||||||
if (const ResultCode result{CheckMemoryState(
|
if (const ResultCode result{CheckMemoryState(
|
||||||
nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
|
nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
|
||||||
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
||||||
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
|
||||||
KMemoryAttribute::DeviceSharedAndUncached)};
|
KMemoryAttribute::DeviceSharedAndUncached)};
|
||||||
|
@ -1068,7 +1068,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
|
||||||
KMemoryPermission old_perm{};
|
KMemoryPermission old_perm{};
|
||||||
|
|
||||||
if (const ResultCode result{CheckMemoryState(
|
if (const ResultCode result{CheckMemoryState(
|
||||||
nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
||||||
KMemoryState::FlagCanCodeMemory, KMemoryPermission::All,
|
KMemoryState::FlagCanCodeMemory, KMemoryPermission::All,
|
||||||
KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
|
KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
|
||||||
result.IsError()) {
|
result.IsError()) {
|
||||||
|
@ -1095,7 +1095,7 @@ ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
|
||||||
KMemoryPermission old_perm{};
|
KMemoryPermission old_perm{};
|
||||||
|
|
||||||
if (const ResultCode result{CheckMemoryState(
|
if (const ResultCode result{CheckMemoryState(
|
||||||
nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
||||||
KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None,
|
KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None,
|
||||||
KMemoryAttribute::All, KMemoryAttribute::Locked)};
|
KMemoryAttribute::All, KMemoryAttribute::Locked)};
|
||||||
result.IsError()) {
|
result.IsError()) {
|
||||||
|
@ -1225,18 +1225,19 @@ constexpr VAddr KPageTable::GetRegionAddress(KMemoryState state) const {
|
||||||
return alias_region_start;
|
return alias_region_start;
|
||||||
case KMemoryState::Stack:
|
case KMemoryState::Stack:
|
||||||
return stack_region_start;
|
return stack_region_start;
|
||||||
case KMemoryState::Io:
|
|
||||||
case KMemoryState::Static:
|
case KMemoryState::Static:
|
||||||
case KMemoryState::ThreadLocal:
|
case KMemoryState::ThreadLocal:
|
||||||
return kernel_map_region_start;
|
return kernel_map_region_start;
|
||||||
|
case KMemoryState::Io:
|
||||||
case KMemoryState::Shared:
|
case KMemoryState::Shared:
|
||||||
case KMemoryState::AliasCode:
|
case KMemoryState::AliasCode:
|
||||||
case KMemoryState::AliasCodeData:
|
case KMemoryState::AliasCodeData:
|
||||||
case KMemoryState::Transferred:
|
case KMemoryState::Transfered:
|
||||||
case KMemoryState::SharedTransferred:
|
case KMemoryState::SharedTransfered:
|
||||||
case KMemoryState::SharedCode:
|
case KMemoryState::SharedCode:
|
||||||
case KMemoryState::GeneratedCode:
|
case KMemoryState::GeneratedCode:
|
||||||
case KMemoryState::CodeOut:
|
case KMemoryState::CodeOut:
|
||||||
|
case KMemoryState::Coverage:
|
||||||
return alias_code_region_start;
|
return alias_code_region_start;
|
||||||
case KMemoryState::Code:
|
case KMemoryState::Code:
|
||||||
case KMemoryState::CodeData:
|
case KMemoryState::CodeData:
|
||||||
|
@ -1260,18 +1261,19 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
|
||||||
return alias_region_end - alias_region_start;
|
return alias_region_end - alias_region_start;
|
||||||
case KMemoryState::Stack:
|
case KMemoryState::Stack:
|
||||||
return stack_region_end - stack_region_start;
|
return stack_region_end - stack_region_start;
|
||||||
case KMemoryState::Io:
|
|
||||||
case KMemoryState::Static:
|
case KMemoryState::Static:
|
||||||
case KMemoryState::ThreadLocal:
|
case KMemoryState::ThreadLocal:
|
||||||
return kernel_map_region_end - kernel_map_region_start;
|
return kernel_map_region_end - kernel_map_region_start;
|
||||||
|
case KMemoryState::Io:
|
||||||
case KMemoryState::Shared:
|
case KMemoryState::Shared:
|
||||||
case KMemoryState::AliasCode:
|
case KMemoryState::AliasCode:
|
||||||
case KMemoryState::AliasCodeData:
|
case KMemoryState::AliasCodeData:
|
||||||
case KMemoryState::Transferred:
|
case KMemoryState::Transfered:
|
||||||
case KMemoryState::SharedTransferred:
|
case KMemoryState::SharedTransfered:
|
||||||
case KMemoryState::SharedCode:
|
case KMemoryState::SharedCode:
|
||||||
case KMemoryState::GeneratedCode:
|
case KMemoryState::GeneratedCode:
|
||||||
case KMemoryState::CodeOut:
|
case KMemoryState::CodeOut:
|
||||||
|
case KMemoryState::Coverage:
|
||||||
return alias_code_region_end - alias_code_region_start;
|
return alias_code_region_end - alias_code_region_start;
|
||||||
case KMemoryState::Code:
|
case KMemoryState::Code:
|
||||||
case KMemoryState::CodeData:
|
case KMemoryState::CodeData:
|
||||||
|
@ -1283,15 +1285,18 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const {
|
bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const {
|
||||||
const VAddr end{addr + size};
|
const VAddr end = addr + size;
|
||||||
const VAddr last{end - 1};
|
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)};
|
|
||||||
|
|
||||||
|
const VAddr region_start = this->GetRegionAddress(state);
|
||||||
|
const size_t region_size = this->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 ||
|
||||||
|
heap_region_start == heap_region_end);
|
||||||
|
const bool is_in_alias = !(end <= alias_region_start || alias_region_end <= addr ||
|
||||||
|
alias_region_start == alias_region_end);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case KMemoryState::Free:
|
case KMemoryState::Free:
|
||||||
case KMemoryState::Kernel:
|
case KMemoryState::Kernel:
|
||||||
|
@ -1305,11 +1310,12 @@ bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) co
|
||||||
case KMemoryState::AliasCodeData:
|
case KMemoryState::AliasCodeData:
|
||||||
case KMemoryState::Stack:
|
case KMemoryState::Stack:
|
||||||
case KMemoryState::ThreadLocal:
|
case KMemoryState::ThreadLocal:
|
||||||
case KMemoryState::Transferred:
|
case KMemoryState::Transfered:
|
||||||
case KMemoryState::SharedTransferred:
|
case KMemoryState::SharedTransfered:
|
||||||
case KMemoryState::SharedCode:
|
case KMemoryState::SharedCode:
|
||||||
case KMemoryState::GeneratedCode:
|
case KMemoryState::GeneratedCode:
|
||||||
case KMemoryState::CodeOut:
|
case KMemoryState::CodeOut:
|
||||||
|
case KMemoryState::Coverage:
|
||||||
return is_in_region && !is_in_heap && !is_in_alias;
|
return is_in_region && !is_in_heap && !is_in_alias;
|
||||||
case KMemoryState::Normal:
|
case KMemoryState::Normal:
|
||||||
ASSERT(is_in_heap);
|
ASSERT(is_in_heap);
|
||||||
|
@ -1324,91 +1330,29 @@ bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
|
ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
|
||||||
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
|
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||||
|
KMemoryAttribute attr) const {
|
||||||
|
// Validate the states match expectation.
|
||||||
|
R_UNLESS((info.state & state_mask) == state, ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS((info.perm & perm_mask) == perm, ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS((info.attribute & attr_mask) == attr, ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode KPageTable::CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr,
|
||||||
|
std::size_t size, KMemoryState state_mask,
|
||||||
KMemoryState state, KMemoryPermission perm_mask,
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
KMemoryPermission perm,
|
KMemoryPermission perm,
|
||||||
KMemoryAttribute attr_mask,
|
KMemoryAttribute attr_mask,
|
||||||
KMemoryAttribute attr) const {
|
KMemoryAttribute attr) const {
|
||||||
// Validate the states match expectation
|
ASSERT(this->IsLockedByCurrentThread());
|
||||||
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 ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
|
||||||
KMemoryAttribute* out_attr, VAddr addr, std::size_t size,
|
|
||||||
KMemoryState state_mask, KMemoryState state,
|
|
||||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
|
||||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
|
||||||
KMemoryAttribute ignore_attr) {
|
|
||||||
std::lock_guard lock{page_table_lock};
|
|
||||||
|
|
||||||
// Get information about the first block
|
|
||||||
const VAddr last_addr{addr + size - 1};
|
|
||||||
KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)};
|
|
||||||
KMemoryInfo info{it->GetMemoryInfo()};
|
|
||||||
|
|
||||||
// Validate all blocks in the range have correct state
|
|
||||||
const KMemoryState first_state{info.state};
|
|
||||||
const KMemoryPermission first_perm{info.perm};
|
|
||||||
const KMemoryAttribute 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<KMemoryAttribute>(ignore_attr)) ==
|
|
||||||
(first_attr | static_cast<KMemoryAttribute>(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<KMemoryAttribute>(~ignore_attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
|
|
||||||
KMemoryState state_mask, KMemoryState state,
|
|
||||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
|
||||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) const {
|
|
||||||
// Get information about the first block.
|
// Get information about the first block.
|
||||||
const VAddr last_addr = addr + size - 1;
|
const VAddr last_addr = addr + size - 1;
|
||||||
KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)};
|
KMemoryBlockManager::const_iterator it = block_manager->FindIterator(addr);
|
||||||
KMemoryInfo info = it->GetMemoryInfo();
|
KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
// If the start address isn't aligned, we need a block.
|
// If the start address isn't aligned, we need a block.
|
||||||
|
@ -1417,7 +1361,7 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Validate against the provided masks.
|
// Validate against the provided masks.
|
||||||
R_TRY(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||||
|
|
||||||
// Break once we're done.
|
// Break once we're done.
|
||||||
if (last_addr <= info.GetLastAddress()) {
|
if (last_addr <= info.GetLastAddress()) {
|
||||||
|
@ -1426,6 +1370,7 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s
|
||||||
|
|
||||||
// Advance our iterator.
|
// Advance our iterator.
|
||||||
it++;
|
it++;
|
||||||
|
ASSERT(it != block_manager->cend());
|
||||||
info = it->GetMemoryInfo();
|
info = it->GetMemoryInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1440,4 +1385,66 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||||
|
KMemoryAttribute* out_attr, std::size_t* out_blocks_needed,
|
||||||
|
VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||||
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
|
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||||
|
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
|
||||||
|
ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
// Get information about the first block.
|
||||||
|
const VAddr last_addr = addr + size - 1;
|
||||||
|
KMemoryBlockManager::const_iterator it = block_manager->FindIterator(addr);
|
||||||
|
KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
|
// If the start address isn't aligned, we need a block.
|
||||||
|
const size_t blocks_for_start_align =
|
||||||
|
(Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
|
||||||
|
|
||||||
|
// Validate all blocks in the range have correct state.
|
||||||
|
const KMemoryState first_state = info.state;
|
||||||
|
const KMemoryPermission first_perm = info.perm;
|
||||||
|
const KMemoryAttribute first_attr = info.attribute;
|
||||||
|
while (true) {
|
||||||
|
// Validate the current block.
|
||||||
|
R_UNLESS(info.state == first_state, ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS(info.perm == first_perm, ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS((info.attribute | ignore_attr) == (first_attr | ignore_attr),
|
||||||
|
ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Validate against the provided masks.
|
||||||
|
R_TRY(this->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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the end address isn't aligned, we need a block.
|
||||||
|
const size_t blocks_for_end_align =
|
||||||
|
(Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
||||||
|
|
||||||
|
// Write output state.
|
||||||
|
if (out_state != nullptr) {
|
||||||
|
*out_state = first_state;
|
||||||
|
}
|
||||||
|
if (out_perm != nullptr) {
|
||||||
|
*out_perm = first_perm;
|
||||||
|
}
|
||||||
|
if (out_attr != nullptr) {
|
||||||
|
*out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
|
||||||
|
}
|
||||||
|
if (out_blocks_needed != nullptr) {
|
||||||
|
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
||||||
|
}
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -102,28 +102,50 @@ private:
|
||||||
constexpr VAddr GetRegionAddress(KMemoryState state) const;
|
constexpr VAddr GetRegionAddress(KMemoryState state) const;
|
||||||
constexpr std::size_t GetRegionSize(KMemoryState state) const;
|
constexpr std::size_t GetRegionSize(KMemoryState state) const;
|
||||||
|
|
||||||
constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
|
ResultCode CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr,
|
||||||
|
std::size_t size, KMemoryState state_mask,
|
||||||
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
|
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||||
|
KMemoryAttribute attr) const;
|
||||||
|
ResultCode CheckMemoryStateContiguous(VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||||
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
|
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||||
|
KMemoryAttribute attr) const {
|
||||||
|
return this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask,
|
||||||
|
perm, attr_mask, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
|
||||||
KMemoryState state, KMemoryPermission perm_mask,
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||||
KMemoryAttribute attr) const;
|
KMemoryAttribute attr) const;
|
||||||
ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
|
||||||
KMemoryAttribute* out_attr, VAddr addr, std::size_t size,
|
KMemoryAttribute* out_attr, std::size_t* out_blocks_needed,
|
||||||
KMemoryState state_mask, KMemoryState state,
|
VAddr addr, std::size_t size, KMemoryState state_mask,
|
||||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
|
||||||
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
|
||||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr);
|
|
||||||
ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask,
|
|
||||||
KMemoryState state, KMemoryPermission perm_mask,
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||||
KMemoryAttribute attr,
|
KMemoryAttribute attr,
|
||||||
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) {
|
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||||
return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
|
ResultCode CheckMemoryState(std::size_t* out_blocks_needed, VAddr addr, std::size_t size,
|
||||||
perm, attr_mask, attr, ignore_attr);
|
|
||||||
}
|
|
||||||
ResultCode CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
|
|
||||||
KMemoryState state_mask, KMemoryState state,
|
KMemoryState state_mask, KMemoryState state,
|
||||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
|
KMemoryAttribute attr_mask, KMemoryAttribute attr,
|
||||||
|
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||||
|
return CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size,
|
||||||
|
state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr);
|
||||||
|
}
|
||||||
|
ResultCode CheckMemoryState(VAddr addr, size_t size, KMemoryState state_mask,
|
||||||
|
KMemoryState state, KMemoryPermission perm_mask,
|
||||||
|
KMemoryPermission perm, KMemoryAttribute attr_mask,
|
||||||
|
KMemoryAttribute attr,
|
||||||
|
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||||
|
return this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm,
|
||||||
|
attr_mask, attr, ignore_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLockedByCurrentThread() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::recursive_mutex page_table_lock;
|
std::recursive_mutex page_table_lock;
|
||||||
std::unique_ptr<KMemoryBlockManager> block_manager;
|
std::unique_ptr<KMemoryBlockManager> block_manager;
|
||||||
|
|
|
@ -32,6 +32,7 @@ enum class MemoryState : u32 {
|
||||||
Kernel = 0x13,
|
Kernel = 0x13,
|
||||||
GeneratedCode = 0x14,
|
GeneratedCode = 0x14,
|
||||||
CodeOut = 0x15,
|
CodeOut = 0x15,
|
||||||
|
Coverage = 0x16,
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(MemoryState);
|
DECLARE_ENUM_FLAG_OPERATORS(MemoryState);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue