mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 05:51:51 +01:00
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:
parent
cc71e7b56c
commit
7f24c7b857
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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};
|
||||
|
@ -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...);
|
||||
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user