From 7f24c7b8576caf1aeab66f6375baeedd976cb944 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 30 Oct 2022 16:26:08 +0000 Subject: [PATCH] Store KMemory object ptrs in memory class to avoid linear-time unmap This is quite a horrible solution but fixing it properly would require a whole rewrite of how we handle memory. --- app/src/main/cpp/skyline/kernel/memory.cpp | 1 + app/src/main/cpp/skyline/kernel/memory.h | 7 +++++- app/src/main/cpp/skyline/kernel/svc.cpp | 25 +++++++++++-------- .../skyline/kernel/types/KPrivateMemory.cpp | 8 ++++-- .../cpp/skyline/kernel/types/KPrivateMemory.h | 3 ++- .../cpp/skyline/kernel/types/KProcess.cpp | 8 +++--- .../main/cpp/skyline/kernel/types/KProcess.h | 2 +- .../skyline/kernel/types/KSharedMemory.cpp | 5 +++- 8 files changed, 38 insertions(+), 21 deletions(-) diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index 9cd2075f..d8b16328 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -210,6 +210,7 @@ namespace skyline::kernel { lower->state = chunk.state; lower->permission = chunk.permission; lower->attributes = chunk.attributes; + lower->memory = chunk.memory; } else if (lower->ptr + lower->size > chunk.ptr + chunk.size) { auto lowerExtension{*lower}; lowerExtension.ptr = chunk.ptr + chunk.size; diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 1b3b4efb..f6266722 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -8,6 +8,10 @@ #include namespace skyline { + namespace kernel::type { + class KMemory; + } + namespace memory { union Permission { /** @@ -195,9 +199,10 @@ namespace skyline { memory::Permission permission; memory::MemoryState state; memory::MemoryAttribute attributes; + kernel::type::KMemory *memory{}; constexpr bool IsCompatible(const ChunkDescriptor &chunk) const { - return chunk.permission == permission && chunk.state.value == state.value && chunk.attributes.value == attributes.value; + return chunk.permission == permission && chunk.state.value == state.value && chunk.attributes.value == attributes.value && chunk.memory == memory; } }; diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 752f3b0d..dfe8ecde 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -1067,20 +1067,23 @@ namespace skyline::kernel::svc { auto end{pointer + size}; while (pointer < end) { - auto memory{state.process->GetMemoryObject(pointer)}; - if (memory) { - auto item{static_pointer_cast(memory->item)}; - auto initialSize{item->guest.size()}; - if (item->memoryState == memory::states::Heap) { - if (item->guest.data() >= pointer) { - if (item->guest.size() <= size) { - item->Resize(0); + auto chunk{state.process->memory.Get(pointer)}; + if (chunk && chunk->memory) { + if (chunk->memory->objectType != type::KType::KPrivateMemory) + throw exception("Trying to unmap non-private memory"); + + auto memory{static_cast(chunk->memory)}; + auto initialSize{memory->guest.size()}; + if (memory->memoryState == memory::states::Heap) { + if (memory->guest.data() >= pointer) { + if (memory->guest.size() <= size) { + memory->Resize(0); state.process->CloseHandle(memory->handle); } else { - item->Remap(span{pointer + size, static_cast((pointer + item->guest.size() - item->guest.data())) - size}); + memory->Remap(span{pointer + size, static_cast((pointer + memory->guest.size() - memory->guest.data())) - size}); } - } else if (item->guest.data() < pointer) { - item->Resize(static_cast(pointer - item->guest.data())); + } else if (memory->guest.data() < pointer) { + memory->Resize(static_cast(pointer - memory->guest.data())); } } pointer += initialSize; diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp index 0b37b24f..52d18989 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp @@ -8,14 +8,15 @@ #include "KProcess.h" namespace skyline::kernel::type { - KPrivateMemory::KPrivateMemory(const DeviceState &state, span guest, memory::Permission permission, memory::MemoryState memState) + KPrivateMemory::KPrivateMemory(const DeviceState &state, KHandle handle, span guest, memory::Permission permission, memory::MemoryState memState) : permission(permission), memoryState(memState), + handle(handle), KMemory(state, KType::KPrivateMemory, guest) { if (!state.process->memory.base.contains(guest)) throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", guest.data(), guest.data() + guest.size()); if (!util::IsPageAligned(guest.data()) || !util::IsPageAligned(guest.size())) - throw exception("KPrivateMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", guest.data(), guest.data() + guest.size()); + throw exception("KPrivateMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", guest.data(), guest.data() + guest.size(), guest.size()); if (mprotect(guest.data(), guest.size(), PROT_READ | PROT_WRITE | PROT_EXEC) < 0) // We only need to reprotect as the allocation has already been reserved by the MemoryManager throw exception("An occurred while mapping private memory: {} with 0x{:X} @ 0x{:X}", strerror(errno), guest.data(), guest.size()); @@ -25,6 +26,7 @@ namespace skyline::kernel::type { .size = guest.size(), .permission = permission, .state = memState, + .memory = this, }); } @@ -44,6 +46,7 @@ namespace skyline::kernel::type { .size = nSize - guest.size(), .permission = permission, .state = memoryState, + .memory = this, }); } guest = span{guest.data(), nSize}; @@ -78,6 +81,7 @@ namespace skyline::kernel::type { .size = size, .permission = pPermission, .state = memoryState, + .memory = this, }); } diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h index 5cc71d92..ac873c7d 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h @@ -14,12 +14,13 @@ namespace skyline::kernel::type { public: memory::Permission permission; memory::MemoryState memoryState; + KHandle handle; /** * @param permission The permissions for the allocated memory (As reported to the application, host memory permissions aren't reflected by this) * @note 'ptr' needs to be in guest-reserved address space */ - KPrivateMemory(const DeviceState &state, span guest, memory::Permission permission, memory::MemoryState memState); + KPrivateMemory(const DeviceState &state, KHandle handle, span guest, memory::Permission permission, memory::MemoryState memState); /** * @note There is no check regarding if any expansions will cause the memory mapping to leak into other mappings diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index e1ef6fc0..c1a7c9d7 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -49,7 +49,7 @@ namespace skyline::kernel::type { void KProcess::InitializeHeapTls() { constexpr size_t DefaultHeapSize{0x200000}; - heap = std::make_shared(state, span{state.process->memory.heap.data(), DefaultHeapSize}, memory::Permission{true, true, false}, memory::states::Heap); + heap = std::make_shared(state, 0, span{state.process->memory.heap.data(), DefaultHeapSize}, memory::Permission{true, true, false}, memory::states::Heap); InsertItem(heap); // Insert it into the handle table so GetMemoryObject will contain it tlsExceptionContext = AllocateTlsSlot(); } @@ -61,8 +61,8 @@ namespace skyline::kernel::type { if ((slot = tlsPage->ReserveSlot())) return slot; - slot = tlsPages.empty() ? reinterpret_cast(memory.tlsIo.data()) : ((*(tlsPages.end() - 1))->memory->guest.data() + PAGE_SIZE); - auto tlsPage{std::make_shared(std::make_shared(state, span{slot, PAGE_SIZE}, memory::Permission(true, true, false), memory::states::ThreadLocal))}; + slot = tlsPages.empty() ? reinterpret_cast(memory.tlsIo.data()) : ((*(tlsPages.end() - 1))->memory->guest.data() + constant::PageSize); + auto tlsPage{std::make_shared(std::make_shared(state, 0, span{slot, constant::PageSize}, memory::Permission(true, true, false), memory::states::ThreadLocal))}; tlsPages.push_back(tlsPage); return tlsPage->ReserveSlot(); } @@ -72,7 +72,7 @@ namespace skyline::kernel::type { if (disableThreadCreation) return nullptr; if (!stackTop && threads.empty()) { //!< Main thread stack is created by the kernel and owned by the process - mainThreadStack = std::make_shared(state, span{state.process->memory.stack.data(), state.process->npdm.meta.mainThreadStackSize}, memory::Permission{true, true, false}, memory::states::Stack); + mainThreadStack = std::make_shared(state, 0, span{state.process->memory.stack.data(), state.process->npdm.meta.mainThreadStackSize}, memory::Permission{true, true, false}, memory::states::Stack); stackTop = mainThreadStack->guest.end().base(); } auto thread{NewHandle(this, threads.size(), entry, argument, stackTop, priority ? *priority : state.process->npdm.meta.mainThreadPriority, idealCore ? *idealCore : state.process->npdm.meta.idealCore).item}; diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 162e50e5..628229e3 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -117,7 +117,7 @@ namespace skyline { std::unique_lock lock(handleMutex); std::shared_ptr item; - if constexpr (std::is_same()) + if constexpr (std::is_same() || std::is_same()) item = std::make_shared(state, constant::BaseHandleIndex + handles.size(), args...); else item = std::make_shared(state, args...); diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index 10b6d0f3..acd0cc5a 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -43,6 +43,7 @@ namespace skyline::kernel::type { .attributes = memory::MemoryAttribute{ .isBorrowed = objectType == KType::KTransferMemory, }, + .memory = this }); return guest.data(); @@ -85,6 +86,7 @@ namespace skyline::kernel::type { .attributes = memory::MemoryAttribute{ .isBorrowed = objectType == KType::KTransferMemory, }, + .memory = this }); } } @@ -118,7 +120,8 @@ namespace skyline::kernel::type { .state = memoryState, .attributes = memory::MemoryAttribute{ .isBorrowed = false, - } + }, + .memory = this }); } }