|
|
@@ -505,7 +505,7 @@ Result KPageTable::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress
|
|
|
R_TRY(this->CheckMemoryStateContiguous(
|
|
|
std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState::FlagCanCodeAlias,
|
|
|
KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None,
|
|
|
- KMemoryAttribute::All, KMemoryAttribute::None));
|
|
|
+ KMemoryAttribute::All & ~KMemoryAttribute::PermissionLocked, KMemoryAttribute::None));
|
|
|
|
|
|
// Determine whether any pages being unmapped are code.
|
|
|
bool any_code_pages = false;
|
|
|
@@ -1770,7 +1770,11 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
|
|
|
m_memory_block_manager.UpdateIfMatch(
|
|
|
std::addressof(allocator), address, size / PageSize, KMemoryState::Free,
|
|
|
KMemoryPermission::None, KMemoryAttribute::None, KMemoryState::Normal,
|
|
|
- KMemoryPermission::UserReadWrite, KMemoryAttribute::None);
|
|
|
+ KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
|
|
|
+ address == this->GetAliasRegionStart()
|
|
|
+ ? KMemoryBlockDisableMergeAttribute::Normal
|
|
|
+ : KMemoryBlockDisableMergeAttribute::None,
|
|
|
+ KMemoryBlockDisableMergeAttribute::None);
|
|
|
|
|
|
R_SUCCEED();
|
|
|
}
|
|
|
@@ -1868,6 +1872,13 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
|
|
|
|
|
|
// Iterate over the memory, unmapping as we go.
|
|
|
auto it = m_memory_block_manager.FindIterator(cur_address);
|
|
|
+
|
|
|
+ const auto clear_merge_attr =
|
|
|
+ (it->GetState() == KMemoryState::Normal &&
|
|
|
+ it->GetAddress() == this->GetAliasRegionStart() && it->GetAddress() == address)
|
|
|
+ ? KMemoryBlockDisableMergeAttribute::Normal
|
|
|
+ : KMemoryBlockDisableMergeAttribute::None;
|
|
|
+
|
|
|
while (true) {
|
|
|
// Check that the iterator is valid.
|
|
|
ASSERT(it != m_memory_block_manager.end());
|
|
|
@@ -1905,7 +1916,7 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
|
|
|
m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize,
|
|
|
KMemoryState::Free, KMemoryPermission::None,
|
|
|
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
|
|
|
- KMemoryBlockDisableMergeAttribute::None);
|
|
|
+ clear_merge_attr);
|
|
|
|
|
|
// We succeeded.
|
|
|
R_SUCCEED();
|
|
|
@@ -2650,11 +2661,18 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas
|
|
|
size_t num_allocator_blocks;
|
|
|
constexpr auto AttributeTestMask =
|
|
|
~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared);
|
|
|
- R_TRY(this->CheckMemoryState(
|
|
|
- std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr),
|
|
|
- std::addressof(num_allocator_blocks), addr, size, KMemoryState::FlagCanChangeAttribute,
|
|
|
- KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
|
|
|
- AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
|
|
|
+ const KMemoryState state_test_mask =
|
|
|
+ static_cast<KMemoryState>(((mask & static_cast<u32>(KMemoryAttribute::Uncached))
|
|
|
+ ? static_cast<u32>(KMemoryState::FlagCanChangeAttribute)
|
|
|
+ : 0) |
|
|
|
+ ((mask & static_cast<u32>(KMemoryAttribute::PermissionLocked))
|
|
|
+ ? static_cast<u32>(KMemoryState::FlagCanPermissionLock)
|
|
|
+ : 0));
|
|
|
+ R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm),
|
|
|
+ std::addressof(old_attr), std::addressof(num_allocator_blocks),
|
|
|
+ addr, size, state_test_mask, state_test_mask,
|
|
|
+ KMemoryPermission::None, KMemoryPermission::None,
|
|
|
+ AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
|
|
|
|
|
|
// Create an update allocator.
|
|
|
Result allocator_result{ResultSuccess};
|
|
|
@@ -2662,18 +2680,17 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas
|
|
|
m_memory_block_slab_manager, num_allocator_blocks);
|
|
|
R_TRY(allocator_result);
|
|
|
|
|
|
- // Determine the new attribute.
|
|
|
- const KMemoryAttribute new_attr =
|
|
|
- static_cast<KMemoryAttribute>(((old_attr & static_cast<KMemoryAttribute>(~mask)) |
|
|
|
- static_cast<KMemoryAttribute>(attr & mask)));
|
|
|
-
|
|
|
- // Perform operation.
|
|
|
- this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh);
|
|
|
+ // If we need to, perform a change attribute operation.
|
|
|
+ if (True(KMemoryAttribute::Uncached & static_cast<KMemoryAttribute>(mask))) {
|
|
|
+ // Perform operation.
|
|
|
+ R_TRY(this->Operate(addr, num_pages, old_perm,
|
|
|
+ OperationType::ChangePermissionsAndRefreshAndFlush, 0));
|
|
|
+ }
|
|
|
|
|
|
// Update the blocks.
|
|
|
- m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm,
|
|
|
- new_attr, KMemoryBlockDisableMergeAttribute::None,
|
|
|
- KMemoryBlockDisableMergeAttribute::None);
|
|
|
+ m_memory_block_manager.UpdateAttribute(std::addressof(allocator), addr, num_pages,
|
|
|
+ static_cast<KMemoryAttribute>(mask),
|
|
|
+ static_cast<KMemoryAttribute>(attr));
|
|
|
|
|
|
R_SUCCEED();
|
|
|
}
|
|
|
@@ -3086,6 +3103,7 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
|
|
|
}
|
|
|
case OperationType::ChangePermissions:
|
|
|
case OperationType::ChangePermissionsAndRefresh:
|
|
|
+ case OperationType::ChangePermissionsAndRefreshAndFlush:
|
|
|
break;
|
|
|
default:
|
|
|
ASSERT(false);
|