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.
This commit is contained in:
Billy Laws 2022-10-30 16:26:08 +00:00
parent cc71e7b56c
commit 7f24c7b857
8 changed files with 38 additions and 21 deletions

View File

@ -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;

View File

@ -8,6 +8,10 @@
#include <common/file_descriptor.h>
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;
}
};

View File

@ -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<type::KPrivateMemory>(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<type::KPrivateMemory *>(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<u8>{pointer + size, static_cast<size_t>((pointer + item->guest.size() - item->guest.data())) - size});
memory->Remap(span<u8>{pointer + size, static_cast<size_t>((pointer + memory->guest.size() - memory->guest.data())) - size});
}
} else if (item->guest.data() < pointer) {
item->Resize(static_cast<size_t>(pointer - item->guest.data()));
} else if (memory->guest.data() < pointer) {
memory->Resize(static_cast<size_t>(pointer - memory->guest.data()));
}
}
pointer += initialSize;

View File

@ -8,14 +8,15 @@
#include "KProcess.h"
namespace skyline::kernel::type {
KPrivateMemory::KPrivateMemory(const DeviceState &state, span<u8> guest, memory::Permission permission, memory::MemoryState memState)
KPrivateMemory::KPrivateMemory(const DeviceState &state, KHandle handle, span<u8> 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<u8>{guest.data(), nSize};
@ -78,6 +81,7 @@ namespace skyline::kernel::type {
.size = size,
.permission = pPermission,
.state = memoryState,
.memory = this,
});
}

View File

@ -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<u8> guest, memory::Permission permission, memory::MemoryState memState);
KPrivateMemory(const DeviceState &state, KHandle handle, span<u8> 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

View File

@ -49,7 +49,7 @@ namespace skyline::kernel::type {
void KProcess::InitializeHeapTls() {
constexpr size_t DefaultHeapSize{0x200000};
heap = std::make_shared<KPrivateMemory>(state, span<u8>{state.process->memory.heap.data(), DefaultHeapSize}, memory::Permission{true, true, false}, memory::states::Heap);
heap = std::make_shared<KPrivateMemory>(state, 0, span<u8>{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<u8 *>(memory.tlsIo.data()) : ((*(tlsPages.end() - 1))->memory->guest.data() + PAGE_SIZE);
auto tlsPage{std::make_shared<TlsPage>(std::make_shared<KPrivateMemory>(state, span<u8>{slot, PAGE_SIZE}, memory::Permission(true, true, false), memory::states::ThreadLocal))};
slot = tlsPages.empty() ? reinterpret_cast<u8 *>(memory.tlsIo.data()) : ((*(tlsPages.end() - 1))->memory->guest.data() + constant::PageSize);
auto tlsPage{std::make_shared<TlsPage>(std::make_shared<KPrivateMemory>(state, 0, span<u8>{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<KPrivateMemory>(state, span<u8>{state.process->memory.stack.data(), state.process->npdm.meta.mainThreadStackSize}, memory::Permission{true, true, false}, memory::states::Stack);
mainThreadStack = std::make_shared<KPrivateMemory>(state, 0, span<u8>{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<KThread>(this, threads.size(), entry, argument, stackTop, priority ? *priority : state.process->npdm.meta.mainThreadPriority, idealCore ? *idealCore : state.process->npdm.meta.idealCore).item};

View File

@ -117,7 +117,7 @@ namespace skyline {
std::unique_lock lock(handleMutex);
std::shared_ptr<objectClass> item;
if constexpr (std::is_same<objectClass, KThread>())
if constexpr (std::is_same<objectClass, KThread>() || std::is_same<objectClass, KPrivateMemory>())
item = std::make_shared<objectClass>(state, constant::BaseHandleIndex + handles.size(), args...);
else
item = std::make_shared<objectClass>(state, args...);

View File

@ -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
});
}
}