summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/k_memory_block.h36
-rw-r--r--src/core/hle/kernel/k_page_table.cpp201
-rw-r--r--src/core/hle/kernel/k_page_table.h44
-rw-r--r--src/core/hle/kernel/svc_types.h1
4 files changed, 166 insertions, 116 deletions
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h
index 9e51c33ce..dcca47f1b 100644
--- a/src/core/hle/kernel/k_memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -70,12 +70,12 @@ enum class KMemoryState : u32 {
ThreadLocal =
static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted,
- Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
- FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
- FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
+ Transfered = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
+ FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
+ FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
- SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
- FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
+ SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
+ FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
@@ -93,6 +93,8 @@ enum class KMemoryState : u32 {
GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped |
FlagReferenceCounted | FlagCanDebug,
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted,
+
+ Coverage = static_cast<u32>(Svc::MemoryState::Coverage) | FlagMapped,
};
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::Stack) == 0x005C3C0B);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C);
-static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x015C3C0D);
-static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x005C380E);
+static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x015C3C0D);
+static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x005C380E);
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F);
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
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::GeneratedCode) == 0x00402214);
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
+static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016);
enum class KMemoryPermission : u8 {
None = 0,
@@ -155,7 +158,13 @@ enum class KMemoryPermission : u8 {
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
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 {
@@ -169,6 +178,8 @@ enum class KMemoryAttribute : u8 {
DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared),
Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
+ SetMask = Uncached,
+
IpcAndDeviceMapped = IpcLocked | DeviceShared,
LockedAndIpcLocked = Locked | IpcLocked,
DeviceSharedAndUncached = DeviceShared | Uncached
@@ -215,6 +226,15 @@ struct KMemoryInfo {
constexpr VAddr GetLastAddress() const {
return GetEndAddress() - 1;
}
+ constexpr KMemoryState GetState() const {
+ return state;
+ }
+ constexpr KMemoryAttribute GetAttribute() const {
+ return attribute;
+ }
+ constexpr KMemoryPermission GetPermission() const {
+ return perm;
+ }
};
class KMemoryBlock final {
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 4da509224..e86ded58b 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -305,8 +305,8 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:
KMemoryState state{};
KMemoryPermission perm{};
- CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All,
- KMemoryState::Normal, KMemoryPermission::All,
+ CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size,
+ KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All,
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask,
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};
- CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, KMemoryState::All,
- KMemoryState::Normal, KMemoryPermission::None,
+ CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, nullptr, src_addr, size,
+ KMemoryState::All, KMemoryState::Normal, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::Mask,
KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
KMemoryState state{};
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,
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
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{};
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,
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{};
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,
KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
KMemoryPermission dst_perm{};
- CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, KMemoryState::All,
- KMemoryState::Stack, KMemoryPermission::None,
+ CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, nullptr, dst_addr, size,
+ KMemoryState::All, KMemoryState::Stack, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::Mask,
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
@@ -721,7 +721,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
KMemoryPermission prev_perm{};
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,
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
@@ -782,7 +782,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
KMemoryAttribute attribute{};
CASCADE_CODE(CheckMemoryState(
- &state, nullptr, &attribute, addr, size,
+ &state, nullptr, &attribute, nullptr, addr, size,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All,
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None,
@@ -799,7 +799,7 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
KMemoryState state{};
CASCADE_CODE(
- CheckMemoryState(&state, nullptr, nullptr, addr, size,
+ CheckMemoryState(&state, nullptr, nullptr, nullptr, addr, size,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
@@ -820,7 +820,7 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
KMemoryState old_state;
KMemoryPermission old_perm;
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,
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
@@ -846,7 +846,7 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryA
KMemoryAttribute attribute{};
CASCADE_CODE(CheckMemoryState(
- &state, &perm, &attribute, addr, size, KMemoryState::FlagCanChangeAttribute,
+ &state, &perm, &attribute, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute,
KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
KMemoryAttribute::DeviceSharedAndUncached));
@@ -1019,7 +1019,7 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
KMemoryPermission perm{};
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,
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
KMemoryAttribute::DeviceSharedAndUncached)};
@@ -1042,7 +1042,7 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
KMemoryPermission perm{};
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,
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None,
KMemoryAttribute::DeviceSharedAndUncached)};
@@ -1068,7 +1068,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
KMemoryPermission old_perm{};
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,
KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
result.IsError()) {
@@ -1095,7 +1095,7 @@ ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
KMemoryPermission old_perm{};
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,
KMemoryAttribute::All, KMemoryAttribute::Locked)};
result.IsError()) {
@@ -1225,18 +1225,19 @@ constexpr VAddr KPageTable::GetRegionAddress(KMemoryState state) const {
return alias_region_start;
case KMemoryState::Stack:
return stack_region_start;
- case KMemoryState::Io:
case KMemoryState::Static:
case KMemoryState::ThreadLocal:
return kernel_map_region_start;
+ case KMemoryState::Io:
case KMemoryState::Shared:
case KMemoryState::AliasCode:
case KMemoryState::AliasCodeData:
- case KMemoryState::Transferred:
- case KMemoryState::SharedTransferred:
+ case KMemoryState::Transfered:
+ case KMemoryState::SharedTransfered:
case KMemoryState::SharedCode:
case KMemoryState::GeneratedCode:
case KMemoryState::CodeOut:
+ case KMemoryState::Coverage:
return alias_code_region_start;
case KMemoryState::Code:
case KMemoryState::CodeData:
@@ -1260,18 +1261,19 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
return alias_region_end - alias_region_start;
case KMemoryState::Stack:
return stack_region_end - stack_region_start;
- case KMemoryState::Io:
case KMemoryState::Static:
case KMemoryState::ThreadLocal:
return kernel_map_region_end - kernel_map_region_start;
+ case KMemoryState::Io:
case KMemoryState::Shared:
case KMemoryState::AliasCode:
case KMemoryState::AliasCodeData:
- case KMemoryState::Transferred:
- case KMemoryState::SharedTransferred:
+ case KMemoryState::Transfered:
+ case KMemoryState::SharedTransfered:
case KMemoryState::SharedCode:
case KMemoryState::GeneratedCode:
case KMemoryState::CodeOut:
+ case KMemoryState::Coverage:
return alias_code_region_end - alias_code_region_start;
case KMemoryState::Code:
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 {
- const VAddr end{addr + size};
- const VAddr last{end - 1};
- const VAddr region_start{GetRegionAddress(state)};
- const std::size_t region_size{GetRegionSize(state)};
- const bool is_in_region{region_start <= addr && addr < end &&
- last <= region_start + region_size - 1};
- const bool is_in_heap{!(end <= heap_region_start || heap_region_end <= addr)};
- const bool is_in_alias{!(end <= alias_region_start || alias_region_end <= addr)};
-
+ const VAddr end = addr + size;
+ const VAddr last = end - 1;
+
+ 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) {
case KMemoryState::Free:
case KMemoryState::Kernel:
@@ -1305,11 +1310,12 @@ bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) co
case KMemoryState::AliasCodeData:
case KMemoryState::Stack:
case KMemoryState::ThreadLocal:
- case KMemoryState::Transferred:
- case KMemoryState::SharedTransferred:
+ case KMemoryState::Transfered:
+ case KMemoryState::SharedTransfered:
case KMemoryState::SharedCode:
case KMemoryState::GeneratedCode:
case KMemoryState::CodeOut:
+ case KMemoryState::Coverage:
return is_in_region && !is_in_heap && !is_in_alias;
case KMemoryState::Normal:
ASSERT(is_in_heap);
@@ -1324,100 +1330,91 @@ bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) co
}
}
-constexpr 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
- if ((info.state & state_mask) != state) {
- return ResultInvalidCurrentMemory;
- }
- if ((info.perm & perm_mask) != perm) {
- return ResultInvalidCurrentMemory;
- }
- if ((info.attribute & attr_mask) != attr) {
- return ResultInvalidCurrentMemory;
- }
+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::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};
+ResultCode KPageTable::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 {
+ 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()};
+ // 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};
+ // 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;
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));
+ // Validate against the provided masks.
+ 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()) {
break;
}
- // Advance our iterator
+ // 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);
+ // 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;
+
+ if (out_blocks_needed != nullptr) {
+ *out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
}
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 {
+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)};
+ 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(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.
if (last_addr <= info.GetLastAddress()) {
@@ -1426,6 +1423,7 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s
// Advance our iterator.
it++;
+ ASSERT(it != block_manager->cend());
info = it->GetMemoryInfo();
}
@@ -1433,10 +1431,19 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s
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;
}
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 564410dca..07c1d18ac 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -102,28 +102,50 @@ private:
constexpr VAddr GetRegionAddress(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,
+ KMemoryPermission perm, KMemoryAttribute attr_mask,
+ KMemoryAttribute attr) const;
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,
+ VAddr addr, std::size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask,
+ KMemoryPermission perm, KMemoryAttribute attr_mask,
+ KMemoryAttribute attr,
+ KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
+ ResultCode CheckMemoryState(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 = DefaultMemoryIgnoreAttr);
- ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask,
+ 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) {
- return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
- perm, attr_mask, attr, ignore_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;
}
- ResultCode 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;
std::recursive_mutex page_table_lock;
std::unique_ptr<KMemoryBlockManager> block_manager;
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index ec463b97c..365e22e4e 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -32,6 +32,7 @@ enum class MemoryState : u32 {
Kernel = 0x13,
GeneratedCode = 0x14,
CodeOut = 0x15,
+ Coverage = 0x16,
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryState);