mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 00:45:28 +03: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->state = chunk.state;
|
||||||
lower->permission = chunk.permission;
|
lower->permission = chunk.permission;
|
||||||
lower->attributes = chunk.attributes;
|
lower->attributes = chunk.attributes;
|
||||||
|
lower->memory = chunk.memory;
|
||||||
} else if (lower->ptr + lower->size > chunk.ptr + chunk.size) {
|
} else if (lower->ptr + lower->size > chunk.ptr + chunk.size) {
|
||||||
auto lowerExtension{*lower};
|
auto lowerExtension{*lower};
|
||||||
lowerExtension.ptr = chunk.ptr + chunk.size;
|
lowerExtension.ptr = chunk.ptr + chunk.size;
|
||||||
|
@ -8,6 +8,10 @@
|
|||||||
#include <common/file_descriptor.h>
|
#include <common/file_descriptor.h>
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
|
namespace kernel::type {
|
||||||
|
class KMemory;
|
||||||
|
}
|
||||||
|
|
||||||
namespace memory {
|
namespace memory {
|
||||||
union Permission {
|
union Permission {
|
||||||
/**
|
/**
|
||||||
@ -195,9 +199,10 @@ namespace skyline {
|
|||||||
memory::Permission permission;
|
memory::Permission permission;
|
||||||
memory::MemoryState state;
|
memory::MemoryState state;
|
||||||
memory::MemoryAttribute attributes;
|
memory::MemoryAttribute attributes;
|
||||||
|
kernel::type::KMemory *memory{};
|
||||||
|
|
||||||
constexpr bool IsCompatible(const ChunkDescriptor &chunk) const {
|
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};
|
auto end{pointer + size};
|
||||||
while (pointer < end) {
|
while (pointer < end) {
|
||||||
auto memory{state.process->GetMemoryObject(pointer)};
|
auto chunk{state.process->memory.Get(pointer)};
|
||||||
if (memory) {
|
if (chunk && chunk->memory) {
|
||||||
auto item{static_pointer_cast<type::KPrivateMemory>(memory->item)};
|
if (chunk->memory->objectType != type::KType::KPrivateMemory)
|
||||||
auto initialSize{item->guest.size()};
|
throw exception("Trying to unmap non-private memory");
|
||||||
if (item->memoryState == memory::states::Heap) {
|
|
||||||
if (item->guest.data() >= pointer) {
|
auto memory{static_cast<type::KPrivateMemory *>(chunk->memory)};
|
||||||
if (item->guest.size() <= size) {
|
auto initialSize{memory->guest.size()};
|
||||||
item->Resize(0);
|
if (memory->memoryState == memory::states::Heap) {
|
||||||
|
if (memory->guest.data() >= pointer) {
|
||||||
|
if (memory->guest.size() <= size) {
|
||||||
|
memory->Resize(0);
|
||||||
state.process->CloseHandle(memory->handle);
|
state.process->CloseHandle(memory->handle);
|
||||||
} else {
|
} 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) {
|
} else if (memory->guest.data() < pointer) {
|
||||||
item->Resize(static_cast<size_t>(pointer - item->guest.data()));
|
memory->Resize(static_cast<size_t>(pointer - memory->guest.data()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pointer += initialSize;
|
pointer += initialSize;
|
||||||
|
@ -8,14 +8,15 @@
|
|||||||
#include "KProcess.h"
|
#include "KProcess.h"
|
||||||
|
|
||||||
namespace skyline::kernel::type {
|
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),
|
: permission(permission),
|
||||||
memoryState(memState),
|
memoryState(memState),
|
||||||
|
handle(handle),
|
||||||
KMemory(state, KType::KPrivateMemory, guest) {
|
KMemory(state, KType::KPrivateMemory, guest) {
|
||||||
if (!state.process->memory.base.contains(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());
|
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()))
|
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
|
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());
|
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(),
|
.size = guest.size(),
|
||||||
.permission = permission,
|
.permission = permission,
|
||||||
.state = memState,
|
.state = memState,
|
||||||
|
.memory = this,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ namespace skyline::kernel::type {
|
|||||||
.size = nSize - guest.size(),
|
.size = nSize - guest.size(),
|
||||||
.permission = permission,
|
.permission = permission,
|
||||||
.state = memoryState,
|
.state = memoryState,
|
||||||
|
.memory = this,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
guest = span<u8>{guest.data(), nSize};
|
guest = span<u8>{guest.data(), nSize};
|
||||||
@ -78,6 +81,7 @@ namespace skyline::kernel::type {
|
|||||||
.size = size,
|
.size = size,
|
||||||
.permission = pPermission,
|
.permission = pPermission,
|
||||||
.state = memoryState,
|
.state = memoryState,
|
||||||
|
.memory = this,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,12 +14,13 @@ namespace skyline::kernel::type {
|
|||||||
public:
|
public:
|
||||||
memory::Permission permission;
|
memory::Permission permission;
|
||||||
memory::MemoryState memoryState;
|
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)
|
* @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
|
* @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
|
* @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() {
|
void KProcess::InitializeHeapTls() {
|
||||||
constexpr size_t DefaultHeapSize{0x200000};
|
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
|
InsertItem(heap); // Insert it into the handle table so GetMemoryObject will contain it
|
||||||
tlsExceptionContext = AllocateTlsSlot();
|
tlsExceptionContext = AllocateTlsSlot();
|
||||||
}
|
}
|
||||||
@ -61,8 +61,8 @@ namespace skyline::kernel::type {
|
|||||||
if ((slot = tlsPage->ReserveSlot()))
|
if ((slot = tlsPage->ReserveSlot()))
|
||||||
return slot;
|
return slot;
|
||||||
|
|
||||||
slot = tlsPages.empty() ? reinterpret_cast<u8 *>(memory.tlsIo.data()) : ((*(tlsPages.end() - 1))->memory->guest.data() + PAGE_SIZE);
|
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, span<u8>{slot, PAGE_SIZE}, memory::Permission(true, true, false), memory::states::ThreadLocal))};
|
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);
|
tlsPages.push_back(tlsPage);
|
||||||
return tlsPage->ReserveSlot();
|
return tlsPage->ReserveSlot();
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ namespace skyline::kernel::type {
|
|||||||
if (disableThreadCreation)
|
if (disableThreadCreation)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!stackTop && threads.empty()) { //!< Main thread stack is created by the kernel and owned by the process
|
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();
|
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};
|
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::unique_lock lock(handleMutex);
|
||||||
|
|
||||||
std::shared_ptr<objectClass> item;
|
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...);
|
item = std::make_shared<objectClass>(state, constant::BaseHandleIndex + handles.size(), args...);
|
||||||
else
|
else
|
||||||
item = std::make_shared<objectClass>(state, args...);
|
item = std::make_shared<objectClass>(state, args...);
|
||||||
|
@ -43,6 +43,7 @@ namespace skyline::kernel::type {
|
|||||||
.attributes = memory::MemoryAttribute{
|
.attributes = memory::MemoryAttribute{
|
||||||
.isBorrowed = objectType == KType::KTransferMemory,
|
.isBorrowed = objectType == KType::KTransferMemory,
|
||||||
},
|
},
|
||||||
|
.memory = this
|
||||||
});
|
});
|
||||||
|
|
||||||
return guest.data();
|
return guest.data();
|
||||||
@ -85,6 +86,7 @@ namespace skyline::kernel::type {
|
|||||||
.attributes = memory::MemoryAttribute{
|
.attributes = memory::MemoryAttribute{
|
||||||
.isBorrowed = objectType == KType::KTransferMemory,
|
.isBorrowed = objectType == KType::KTransferMemory,
|
||||||
},
|
},
|
||||||
|
.memory = this
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +120,8 @@ namespace skyline::kernel::type {
|
|||||||
.state = memoryState,
|
.state = memoryState,
|
||||||
.attributes = memory::MemoryAttribute{
|
.attributes = memory::MemoryAttribute{
|
||||||
.isBorrowed = false,
|
.isBorrowed = false,
|
||||||
}
|
},
|
||||||
|
.memory = this
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user