mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
kern: track mapped ipc server memory in page table
This commit is contained in:
parent
53e7aa0a20
commit
60b5bd73b7
7 changed files with 40 additions and 29 deletions
|
@ -176,7 +176,7 @@ namespace ams::kern::arch::arm64 {
|
|||
}
|
||||
|
||||
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
|
||||
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager);
|
||||
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit);
|
||||
Result Finalize();
|
||||
private:
|
||||
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||
|
|
|
@ -30,8 +30,8 @@ namespace ams::kern::arch::arm64 {
|
|||
m_page_table.Activate(id);
|
||||
}
|
||||
|
||||
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager) {
|
||||
return m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager);
|
||||
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
|
||||
return m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager, resource_limit);
|
||||
}
|
||||
|
||||
void Finalize() { m_page_table.Finalize(); }
|
||||
|
@ -216,8 +216,8 @@ namespace ams::kern::arch::arm64 {
|
|||
return m_page_table.SetupForIpc(out_dst_addr, size, src_addr, src_page_table.m_page_table, test_perm, dst_state, send);
|
||||
}
|
||||
|
||||
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process) {
|
||||
return m_page_table.CleanupForIpcServer(address, size, dst_state, server_process);
|
||||
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
||||
return m_page_table.CleanupForIpcServer(address, size, dst_state);
|
||||
}
|
||||
|
||||
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
||||
|
|
|
@ -47,6 +47,8 @@ namespace ams::kern {
|
|||
static_assert(std::is_trivial<KPageProperties>::value);
|
||||
static_assert(sizeof(KPageProperties) == sizeof(u32));
|
||||
|
||||
class KResourceLimit;
|
||||
|
||||
class KPageTableBase {
|
||||
NON_COPYABLE(KPageTableBase);
|
||||
NON_MOVEABLE(KPageTableBase);
|
||||
|
@ -150,6 +152,7 @@ namespace ams::kern {
|
|||
size_t m_max_heap_size{};
|
||||
size_t m_mapped_physical_memory_size{};
|
||||
size_t m_mapped_unsafe_physical_memory{};
|
||||
size_t m_mapped_ipc_server_memory{};
|
||||
mutable KLightLock m_general_lock{};
|
||||
mutable KLightLock m_map_physical_memory_lock{};
|
||||
KPageTableImpl m_impl{};
|
||||
|
@ -161,6 +164,7 @@ namespace ams::kern {
|
|||
bool m_enable_device_address_space_merge{};
|
||||
KMemoryBlockSlabManager *m_memory_block_slab_manager{};
|
||||
KBlockInfoManager *m_block_info_manager{};
|
||||
KResourceLimit *m_resource_limit{};
|
||||
const KMemoryRegion *m_cached_physical_linear_region{};
|
||||
const KMemoryRegion *m_cached_physical_heap_region{};
|
||||
const KMemoryRegion *m_cached_virtual_heap_region{};
|
||||
|
@ -171,7 +175,7 @@ namespace ams::kern {
|
|||
constexpr KPageTableBase() { /* ... */ }
|
||||
|
||||
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
|
||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager);
|
||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit);
|
||||
|
||||
void Finalize();
|
||||
|
||||
|
@ -372,7 +376,7 @@ namespace ams::kern {
|
|||
Result CopyMemoryFromHeapToHeapWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
||||
|
||||
Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send);
|
||||
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process);
|
||||
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
|
||||
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
|
||||
|
||||
Result MapPhysicalMemory(KProcessAddress address, size_t size);
|
||||
|
|
|
@ -181,7 +181,7 @@ namespace ams::kern::arch::arm64 {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager) {
|
||||
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
|
||||
/* The input ID isn't actually used. */
|
||||
MESOSPHERE_UNUSED(id);
|
||||
|
||||
|
@ -202,7 +202,7 @@ namespace ams::kern::arch::arm64 {
|
|||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
||||
const KProcessAddress as_start = 0;
|
||||
const KProcessAddress as_end = (1ul << as_width);
|
||||
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager));
|
||||
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager, resource_limit));
|
||||
|
||||
/* We succeeded! */
|
||||
table_guard.Cancel();
|
||||
|
|
|
@ -43,9 +43,11 @@ namespace ams::kern {
|
|||
m_max_heap_size = 0;
|
||||
m_mapped_physical_memory_size = 0;
|
||||
m_mapped_unsafe_physical_memory = 0;
|
||||
m_mapped_ipc_server_memory = 0;
|
||||
|
||||
m_memory_block_slab_manager = std::addressof(Kernel::GetSystemMemoryBlockManager());
|
||||
m_block_info_manager = std::addressof(Kernel::GetBlockInfoManager());
|
||||
m_resource_limit = std::addressof(Kernel::GetSystemResourceLimit());
|
||||
|
||||
m_allocate_option = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
m_heap_fill_value = MemoryFillValue_Zero;
|
||||
|
@ -65,7 +67,7 @@ namespace ams::kern {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager) {
|
||||
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit) {
|
||||
/* Validate the region. */
|
||||
MESOSPHERE_ABORT_UNLESS(start <= code_address);
|
||||
MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size);
|
||||
|
@ -131,6 +133,7 @@ namespace ams::kern {
|
|||
m_is_kernel = false;
|
||||
m_memory_block_slab_manager = mem_block_slab_manager;
|
||||
m_block_info_manager = block_info_manager;
|
||||
m_resource_limit = resource_limit;
|
||||
|
||||
/* Determine the region we can place our undetermineds in. */
|
||||
KProcessAddress alloc_start;
|
||||
|
@ -227,8 +230,9 @@ namespace ams::kern {
|
|||
/* Set heap and fill members. */
|
||||
m_current_heap_end = m_heap_region_start;
|
||||
m_max_heap_size = 0;
|
||||
m_mapped_physical_memory_size = 0;
|
||||
m_mapped_physical_memory_size = 0;
|
||||
m_mapped_unsafe_physical_memory = 0;
|
||||
m_mapped_ipc_server_memory = 0;
|
||||
|
||||
const bool fill_memory = KTargetSystem::IsDebugMemoryFillEnabled();
|
||||
m_heap_fill_value = fill_memory ? MemoryFillValue_Heap : MemoryFillValue_Zero;
|
||||
|
@ -283,6 +287,11 @@ namespace ams::kern {
|
|||
Kernel::GetUnsafeMemory().Release(m_mapped_unsafe_physical_memory);
|
||||
}
|
||||
|
||||
/* Release any ipc server memory. */
|
||||
if (m_mapped_ipc_server_memory) {
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, m_mapped_ipc_server_memory);
|
||||
}
|
||||
|
||||
/* Invalidate the entire instruction cache. */
|
||||
cpu::InvalidateEntireInstructionCache();
|
||||
}
|
||||
|
@ -1507,7 +1516,7 @@ namespace ams::kern {
|
|||
R_TRY(this->Operate(updater.GetPageList(), m_heap_region_start + size, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||
|
||||
/* Release the memory from the resource limit. */
|
||||
GetCurrentProcess().ReleaseResource(ams::svc::LimitableResource_PhysicalMemoryMax, num_pages * PageSize);
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, num_pages * PageSize);
|
||||
|
||||
/* Apply the memory block update. */
|
||||
m_memory_block_manager.Update(std::addressof(allocator), m_heap_region_start + size, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, size == 0 ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None);
|
||||
|
@ -1530,7 +1539,7 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* Reserve memory for the heap extension. */
|
||||
KScopedResourceReservation memory_reservation(GetCurrentProcess().GetResourceLimit(), ams::svc::LimitableResource_PhysicalMemoryMax, allocation_size);
|
||||
KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, allocation_size);
|
||||
R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
|
||||
|
||||
/* Allocate pages for the heap extension. */
|
||||
|
@ -3464,7 +3473,7 @@ namespace ams::kern {
|
|||
|
||||
/* Reserve space for any partial pages we allocate. */
|
||||
const size_t unmapped_size = aligned_src_size - mapping_src_size;
|
||||
KScopedResourceReservation memory_reservation(GetCurrentProcess().GetResourceLimit(), ams::svc::LimitableResource_PhysicalMemoryMax, unmapped_size);
|
||||
KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, unmapped_size);
|
||||
R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
|
||||
|
||||
/* Ensure that we manage page references correctly. */
|
||||
|
@ -3688,7 +3697,7 @@ namespace ams::kern {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPageTableBase::CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process) {
|
||||
Result KPageTableBase::CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
||||
/* Validate the address. */
|
||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
|
@ -3721,12 +3730,10 @@ namespace ams::kern {
|
|||
m_memory_block_manager.Update(std::addressof(allocator), aligned_start, aligned_num_pages, KMemoryState_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);
|
||||
|
||||
/* Release from the resource limit as relevant. */
|
||||
if (auto *resource_limit = server_process->GetResourceLimit(); resource_limit != nullptr) {
|
||||
const KProcessAddress mapping_start = util::AlignUp(GetInteger(address), PageSize);
|
||||
const KProcessAddress mapping_end = util::AlignDown(GetInteger(address) + size, PageSize);
|
||||
const size_t mapping_size = (mapping_start < mapping_end) ? mapping_end - mapping_start : 0;
|
||||
resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_size - mapping_size);
|
||||
}
|
||||
const KProcessAddress mapping_start = util::AlignUp(GetInteger(address), PageSize);
|
||||
const KProcessAddress mapping_end = util::AlignDown(GetInteger(address) + size, PageSize);
|
||||
const size_t mapping_size = (mapping_start < mapping_end) ? mapping_end - mapping_start : 0;
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_size - mapping_size);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
@ -4031,7 +4038,7 @@ namespace ams::kern {
|
|||
/* Allocate and map the memory. */
|
||||
{
|
||||
/* Reserve the memory from the process resource limit. */
|
||||
KScopedResourceReservation memory_reservation(GetCurrentProcess().GetResourceLimit(), ams::svc::LimitableResource_PhysicalMemoryMax, size - mapped_size);
|
||||
KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, size - mapped_size);
|
||||
R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
|
||||
|
||||
/* Allocate pages for the new memory. */
|
||||
|
@ -4439,7 +4446,7 @@ namespace ams::kern {
|
|||
|
||||
/* Release the memory resource. */
|
||||
m_mapped_physical_memory_size -= mapped_size;
|
||||
GetCurrentProcess().ReleaseResource(ams::svc::LimitableResource_PhysicalMemoryMax, mapped_size);
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, mapped_size);
|
||||
|
||||
/* Update memory blocks. */
|
||||
m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
||||
|
|
|
@ -254,7 +254,7 @@ namespace ams::kern {
|
|||
auto *mem_block_manager = std::addressof(is_app ? Kernel::GetApplicationMemoryBlockManager() : Kernel::GetSystemMemoryBlockManager());
|
||||
auto *block_info_manager = std::addressof(Kernel::GetBlockInfoManager());
|
||||
auto *pt_manager = std::addressof(Kernel::GetPageTableManager());
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, mem_block_manager, block_info_manager, pt_manager));
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, mem_block_manager, block_info_manager, pt_manager, res_limit));
|
||||
}
|
||||
auto pt_guard = SCOPE_GUARD { m_page_table.Finalize(); };
|
||||
|
||||
|
@ -359,7 +359,7 @@ namespace ams::kern {
|
|||
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
||||
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
||||
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, mem_block_manager, block_info_manager, pt_manager));
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, mem_block_manager, block_info_manager, pt_manager, res_limit));
|
||||
}
|
||||
auto pt_guard = SCOPE_GUARD { m_page_table.Finalize(); };
|
||||
|
||||
|
|
|
@ -398,17 +398,17 @@ namespace ams::kern {
|
|||
|
||||
/* Cleanup Send mappings. */
|
||||
for (size_t i = 0; i < request->GetSendCount(); ++i) {
|
||||
R_TRY(server_page_table.CleanupForIpcServer(request->GetSendServerAddress(i), request->GetSendSize(i), request->GetSendMemoryState(i), server_process));
|
||||
R_TRY(server_page_table.CleanupForIpcServer(request->GetSendServerAddress(i), request->GetSendSize(i), request->GetSendMemoryState(i)));
|
||||
}
|
||||
|
||||
/* Cleanup Receive mappings. */
|
||||
for (size_t i = 0; i < request->GetReceiveCount(); ++i) {
|
||||
R_TRY(server_page_table.CleanupForIpcServer(request->GetReceiveServerAddress(i), request->GetReceiveSize(i), request->GetReceiveMemoryState(i), server_process));
|
||||
R_TRY(server_page_table.CleanupForIpcServer(request->GetReceiveServerAddress(i), request->GetReceiveSize(i), request->GetReceiveMemoryState(i)));
|
||||
}
|
||||
|
||||
/* Cleanup Exchange mappings. */
|
||||
for (size_t i = 0; i < request->GetExchangeCount(); ++i) {
|
||||
R_TRY(server_page_table.CleanupForIpcServer(request->GetExchangeServerAddress(i), request->GetExchangeSize(i), request->GetExchangeMemoryState(i), server_process));
|
||||
R_TRY(server_page_table.CleanupForIpcServer(request->GetExchangeServerAddress(i), request->GetExchangeSize(i), request->GetExchangeMemoryState(i)));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
|
@ -470,7 +470,7 @@ namespace ams::kern {
|
|||
|
||||
/* Ensure that we clean up on failure. */
|
||||
auto setup_guard = SCOPE_GUARD {
|
||||
dst_page_table.CleanupForIpcServer(dst_address, size, dst_state, request->GetServerProcess());
|
||||
dst_page_table.CleanupForIpcServer(dst_address, size, dst_state);
|
||||
src_page_table.CleanupForIpcClient(src_address, size, dst_state);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue