mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 09:24:16 +01:00
General memman fixups & address review
This commit is contained in:
parent
1513e5f6df
commit
850f616dc7
@ -7,46 +7,36 @@
|
||||
#include "types/KProcess.h"
|
||||
|
||||
namespace skyline::kernel {
|
||||
MemoryManager::MemoryManager(const DeviceState &state) noexcept : state(state), setHeapSize(), chunks() {}
|
||||
MemoryManager::MemoryManager(const DeviceState &state) noexcept : state{state}, processHeapSize{}, memRefs{} {}
|
||||
|
||||
MemoryManager::~MemoryManager() noexcept {
|
||||
if (base.valid() && !base.empty())
|
||||
munmap(reinterpret_cast<void *>(base.data()), base.size());
|
||||
if (addressSpaceType != memory::AddressSpaceType::AddressSpace39Bit)
|
||||
if (codeBase36Bit.valid() && !codeBase36Bit.empty())
|
||||
munmap(reinterpret_cast<void *>(codeBase36Bit.data()), codeBase36Bit.size());
|
||||
}
|
||||
|
||||
std::map<u8 *,ChunkDescriptor>::iterator MemoryManager::upper_bound(u8 *address) {
|
||||
std::map<u8 *,ChunkDescriptor>::iterator result{chunks.begin()};
|
||||
|
||||
if (chunks.size() != 1) [[likely]]
|
||||
while (result->first <= address) {
|
||||
++result;
|
||||
if (result->first + result->second.size == addressSpace.end().base())
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MemoryManager::MapInternal(std::pair<u8 *, ChunkDescriptor> *newDesc) {
|
||||
void MemoryManager::MapInternal(const std::pair<u8 *, ChunkDescriptor> &newDesc) {
|
||||
// The chunk that contains / precedes the new chunk base address
|
||||
auto firstChunkBase{upper_bound(newDesc->first)};
|
||||
while (newDesc->first <= firstChunkBase->first)
|
||||
auto firstChunkBase{chunks.lower_bound(newDesc.first)};
|
||||
if (newDesc.first <= firstChunkBase->first)
|
||||
--firstChunkBase;
|
||||
|
||||
// The chunk that contains / follows the end address of the new chunk
|
||||
auto lastChunkBase{upper_bound(newDesc->first + newDesc->second.size)};
|
||||
while ((newDesc->first + newDesc->second.size) < lastChunkBase->first)
|
||||
auto lastChunkBase{chunks.lower_bound(newDesc.first + newDesc.second.size)};
|
||||
if ((newDesc.first + newDesc.second.size) < lastChunkBase->first)
|
||||
--lastChunkBase;
|
||||
|
||||
ChunkDescriptor firstChunk{firstChunkBase->second};
|
||||
ChunkDescriptor lastChunk{lastChunkBase->second};
|
||||
|
||||
bool needsReprotection{false};
|
||||
bool isUnmapping{newDesc->second.state == memory::states::Unmapped};
|
||||
bool isUnmapping{newDesc.second.state == memory::states::Unmapped};
|
||||
|
||||
// We cut a hole in a single chunk
|
||||
if (firstChunkBase->first == lastChunkBase->first) {
|
||||
if (firstChunk.IsCompatible(newDesc->second)) [[unlikely]]
|
||||
if (firstChunk.IsCompatible(newDesc.second)) [[unlikely]]
|
||||
// No editing necessary
|
||||
return;
|
||||
|
||||
@ -54,15 +44,15 @@ namespace skyline::kernel {
|
||||
needsReprotection = true;
|
||||
|
||||
// We edit the chunk's first half
|
||||
firstChunk.size = static_cast<size_t>(newDesc->first - firstChunkBase->first);
|
||||
firstChunk.size = static_cast<size_t>(newDesc.first - firstChunkBase->first);
|
||||
chunks[firstChunkBase->first] = firstChunk;
|
||||
|
||||
// We create the chunk's second half
|
||||
lastChunk.size = static_cast<size_t>((lastChunkBase->first + lastChunk.size) - (newDesc->first + newDesc->second.size));
|
||||
chunks[newDesc->first + newDesc->second.size] = lastChunk;
|
||||
lastChunk.size = static_cast<size_t>((lastChunkBase->first + lastChunk.size) - (newDesc.first + newDesc.second.size));
|
||||
chunks.insert({newDesc.first + newDesc.second.size, lastChunk});
|
||||
|
||||
// Insert new chunk in between
|
||||
chunks[newDesc->first] = newDesc->second;
|
||||
chunks.insert(newDesc);
|
||||
} else {
|
||||
// If there are descriptors between first and last chunk, delete them
|
||||
if ((firstChunkBase->first + firstChunk.size) != lastChunkBase->first) {
|
||||
@ -79,13 +69,13 @@ namespace skyline::kernel {
|
||||
|
||||
bool shouldInsert{true};
|
||||
|
||||
if (firstChunk.IsCompatible(newDesc->second)) {
|
||||
if (firstChunk.IsCompatible(newDesc.second)) {
|
||||
shouldInsert = false;
|
||||
|
||||
firstChunk.size = static_cast<size_t>((newDesc->first + newDesc->second.size) - firstChunkBase->first);
|
||||
firstChunk.size = static_cast<size_t>((newDesc.first + newDesc.second.size) - firstChunkBase->first);
|
||||
chunks[firstChunkBase->first] = firstChunk;
|
||||
} else if ((firstChunkBase->first + firstChunk.size) != newDesc->first) {
|
||||
firstChunk.size = static_cast<size_t>(newDesc->first - firstChunkBase->first);
|
||||
} else if ((firstChunkBase->first + firstChunk.size) != newDesc.first) {
|
||||
firstChunk.size = static_cast<size_t>(newDesc.first - firstChunkBase->first);
|
||||
|
||||
chunks[firstChunkBase->first] = firstChunk;
|
||||
|
||||
@ -93,25 +83,25 @@ namespace skyline::kernel {
|
||||
needsReprotection = true;
|
||||
}
|
||||
|
||||
if (lastChunk.IsCompatible(newDesc->second)) {
|
||||
if (lastChunk.IsCompatible(newDesc.second)) {
|
||||
u8 *oldBase{lastChunkBase->first};
|
||||
chunks.erase(lastChunkBase);
|
||||
|
||||
if (shouldInsert) {
|
||||
shouldInsert = false;
|
||||
|
||||
lastChunk.size = static_cast<size_t>((lastChunk.size + oldBase) - (newDesc->first));
|
||||
lastChunk.size = static_cast<size_t>((lastChunk.size + oldBase) - (newDesc.first));
|
||||
|
||||
chunks[newDesc->first] = lastChunk;
|
||||
chunks[newDesc.first] = lastChunk;
|
||||
} else {
|
||||
firstChunk.size = static_cast<size_t>((lastChunk.size + oldBase) - firstChunkBase->first);
|
||||
chunks[firstChunkBase->first] = firstChunk;
|
||||
}
|
||||
} else if ((newDesc->first + newDesc->second.size) != lastChunkBase->first) {
|
||||
lastChunk.size = static_cast<size_t>((lastChunk.size + lastChunkBase->first) - (newDesc->first + newDesc->second.size));
|
||||
} else if ((newDesc.first + newDesc.second.size) != lastChunkBase->first) {
|
||||
lastChunk.size = static_cast<size_t>((lastChunk.size + lastChunkBase->first) - (newDesc.first + newDesc.second.size));
|
||||
|
||||
chunks.erase(lastChunkBase);
|
||||
chunks[newDesc->first + newDesc->second.size] = lastChunk;
|
||||
chunks[newDesc.first + newDesc.second.size] = lastChunk;
|
||||
|
||||
if ((lastChunk.state == memory::states::Unmapped) != isUnmapping)
|
||||
needsReprotection = true;
|
||||
@ -119,49 +109,45 @@ namespace skyline::kernel {
|
||||
|
||||
// Insert if not merged
|
||||
if (shouldInsert)
|
||||
chunks[newDesc->first] = newDesc->second;
|
||||
chunks.insert(newDesc);
|
||||
}
|
||||
|
||||
if (needsReprotection)
|
||||
if (mprotect(newDesc->first, newDesc->second.size, !isUnmapping ? PROT_READ | PROT_WRITE | PROT_EXEC : PROT_NONE)) [[unlikely]]
|
||||
if (mprotect(newDesc.first, newDesc.second.size, !isUnmapping ? PROT_READ | PROT_WRITE | PROT_EXEC : PROT_NONE)) [[unlikely]]
|
||||
Logger::Warn("Reprotection failed: {}", strerror(errno));
|
||||
}
|
||||
|
||||
void MemoryManager::ForeachChunkinRange(span<skyline::u8> memory, auto editCallback) {
|
||||
auto chunkBase{upper_bound(memory.data())};
|
||||
void MemoryManager::ForeachChunkinRange(span<u8> memory, auto editCallback) {
|
||||
auto chunkBase{chunks.lower_bound(memory.data())};
|
||||
if (memory.data() < chunkBase->first)
|
||||
--chunkBase;
|
||||
|
||||
ChunkDescriptor resultChunk{chunkBase->second};
|
||||
|
||||
size_t sizeLeft{memory.size()};
|
||||
|
||||
if (chunkBase->first < memory.data()) {
|
||||
size_t copySize{std::min<size_t>(resultChunk.size - (static_cast<size_t>(memory.data() - chunkBase->first)), memory.size())};
|
||||
if (chunkBase->first < memory.data()) [[unlikely]] {
|
||||
size_t chunkSize{std::min<size_t>(chunkBase->second.size - (static_cast<size_t>(memory.data() - chunkBase->first)), memory.size())};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(memory.data(), resultChunk);
|
||||
temp.second.size = copySize;
|
||||
std::pair<u8 *, ChunkDescriptor> temp{memory.data(), chunkBase->second};
|
||||
temp.second.size = chunkSize;
|
||||
editCallback(temp);
|
||||
|
||||
++chunkBase;
|
||||
resultChunk = chunkBase->second;
|
||||
sizeLeft -= copySize;
|
||||
sizeLeft -= chunkSize;
|
||||
}
|
||||
|
||||
while (sizeLeft) {
|
||||
if (sizeLeft < resultChunk.size) {
|
||||
std::pair<u8 *, ChunkDescriptor> temp(chunkBase->first, resultChunk);
|
||||
if (sizeLeft < chunkBase->second.size) {
|
||||
std::pair<u8 *, ChunkDescriptor> temp(*chunkBase);
|
||||
temp.second.size = sizeLeft;
|
||||
editCallback(temp);
|
||||
break;
|
||||
} else [[likely]] {
|
||||
std::pair<u8 *, ChunkDescriptor> temp(chunkBase->first, resultChunk);
|
||||
std::pair<u8 *, ChunkDescriptor> temp(*chunkBase);
|
||||
|
||||
editCallback(temp);
|
||||
|
||||
sizeLeft = sizeLeft - resultChunk.size;
|
||||
sizeLeft = sizeLeft - chunkBase->second.size;
|
||||
++chunkBase;
|
||||
resultChunk = chunkBase->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -233,32 +219,27 @@ namespace skyline::kernel {
|
||||
|
||||
// Qualcomm KGSL (Kernel Graphic Support Layer/Kernel GPU driver) maps below 35-bits, reserving it causes KGSL to go OOM
|
||||
static constexpr size_t KgslReservedRegionSize{1ULL << 35};
|
||||
|
||||
base = AllocateMappedRange(baseSize, RegionAlignment, KgslReservedRegionSize, addressSpace.size(), false);
|
||||
|
||||
if (type != memory::AddressSpaceType::AddressSpace36Bit) {
|
||||
base = AllocateMappedRange(baseSize, RegionAlignment, KgslReservedRegionSize, addressSpace.size(), false);
|
||||
|
||||
chunks[addressSpace.data()] = ChunkDescriptor{
|
||||
.size = addressSpace.size(),
|
||||
.state = memory::states::Unmapped,
|
||||
};
|
||||
|
||||
code = base;
|
||||
|
||||
} else {
|
||||
codeBase36Bit = AllocateMappedRange(0x78000000, RegionAlignment, 0x8000000, KgslReservedRegionSize, false);
|
||||
base = AllocateMappedRange(baseSize, RegionAlignment, KgslReservedRegionSize, addressSpace.size(), false);
|
||||
code = codeBase36Bit = AllocateMappedRange(0x78000000, RegionAlignment, 0x8000000, KgslReservedRegionSize, false);
|
||||
|
||||
if ((reinterpret_cast<u64>(base.data()) + baseSize) > (1ULL << 36)) {
|
||||
Logger::Warn("Couldn't fit regions into AS! Resizing AS instead!");
|
||||
Logger::Warn("Couldn't fit regions into 36 bit AS! Resizing AS to 39 bits!");
|
||||
addressSpace = span<u8>{reinterpret_cast<u8 *>(0), 1ULL << 39};
|
||||
}
|
||||
}
|
||||
|
||||
chunks[addressSpace.data()] = ChunkDescriptor{
|
||||
// Insert a placeholder element at the end of the map to make sure upper_bound/lower_bound never triggers std::map::end() which is broken
|
||||
chunks = {{addressSpace.data(),{
|
||||
.size = addressSpace.size(),
|
||||
.state = memory::states::Unmapped,
|
||||
};
|
||||
|
||||
code = codeBase36Bit;
|
||||
}
|
||||
}}, {reinterpret_cast<u8 *>(UINT64_MAX), {
|
||||
.state = memory::states::Reserved,
|
||||
}}};
|
||||
}
|
||||
|
||||
void MemoryManager::InitializeRegions(span<u8> codeRegion) {
|
||||
@ -270,11 +251,10 @@ namespace skyline::kernel {
|
||||
|
||||
// As a workaround if we can't place the code region at the base of the AS we mark it as inaccessible heap so rtld doesn't crash
|
||||
if (codeBase36Bit.data() != reinterpret_cast<u8 *>(0x8000000)) {
|
||||
std::pair<u8 *, ChunkDescriptor> tmp(reinterpret_cast<u8 *>(0x8000000), ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(reinterpret_cast<u8 *>(0x8000000),{
|
||||
.size = reinterpret_cast<size_t>(codeBase36Bit.data() - 0x8000000),
|
||||
.state = memory::states::Heap,
|
||||
});
|
||||
MapInternal(&tmp);
|
||||
.state = memory::states::Heap
|
||||
}));
|
||||
}
|
||||
|
||||
// Place code, stack and TLS/IO in the lower 36-bits of the host AS and heap and alias past that
|
||||
@ -298,7 +278,7 @@ namespace skyline::kernel {
|
||||
if (newSize > base.size()) [[unlikely]]
|
||||
throw exception("Guest VMM size has exceeded host carveout size: 0x{:X}/0x{:X} (Code: 0x{:X}/0x{:X})", newSize, base.size(), code.size(), CodeRegionSize);
|
||||
|
||||
if (newSize != base.size())
|
||||
if (newSize != base.size()) [[likely]]
|
||||
munmap(base.end().base(), newSize - base.size());
|
||||
|
||||
break;
|
||||
@ -364,166 +344,151 @@ namespace skyline::kernel {
|
||||
return span<u8>{reinterpret_cast<u8 *>(mirrorBase), totalSize};
|
||||
}
|
||||
|
||||
void MemoryManager::SetLockOnChunks(span<u8> memory, bool value) {
|
||||
std::unique_lock lock(mutex);
|
||||
void MemoryManager::SetRegionBorrowed(span<u8> memory, bool value) {
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) {
|
||||
desc.second.attributes.isBorrowed = value;
|
||||
MapInternal(&desc);
|
||||
MapInternal(desc);
|
||||
});
|
||||
}
|
||||
|
||||
void MemoryManager::SetCPUCachingOnChunks(span<u8> memory, bool value) {
|
||||
std::unique_lock lock(mutex);
|
||||
void MemoryManager::SetRegionCpuCaching(span<u8> memory, bool value) {
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) {
|
||||
desc.second.attributes.isUncached = value;
|
||||
MapInternal(&desc);
|
||||
MapInternal(desc);
|
||||
});
|
||||
}
|
||||
|
||||
void MemoryManager::SetChunkPermission(span<u8> memory, memory::Permission permission) {
|
||||
std::unique_lock lock(mutex);
|
||||
void MemoryManager::SetRegionPermission(span<u8> memory, memory::Permission permission) {
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) {
|
||||
desc.second.permission = permission;
|
||||
MapInternal(&desc);
|
||||
MapInternal(desc);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<std::pair<u8 *, ChunkDescriptor>> MemoryManager::GetChunk(u8 *addr) {
|
||||
std::shared_lock lock(mutex);
|
||||
std::shared_lock lock{mutex};
|
||||
|
||||
if (!addressSpace.contains(addr)) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
auto chunkBase = upper_bound(addr);
|
||||
if (addr < chunkBase->first) [[likely]]
|
||||
auto chunkBase = chunks.lower_bound(addr);
|
||||
if (addr < chunkBase->first)
|
||||
--chunkBase;
|
||||
|
||||
return std::make_optional(*chunkBase);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::MapCodeMemory(span<u8> memory, memory::Permission permission) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = permission,
|
||||
.state = memory::states::Code});
|
||||
|
||||
MapInternal(&temp);
|
||||
.state = memory::states::Code
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::MapMutableCodeMemory(span<u8> memory) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = {true, true, false},
|
||||
.state = memory::states::CodeMutable});
|
||||
|
||||
MapInternal(&temp);
|
||||
.state = memory::states::CodeMutable
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::MapStackMemory(span<u8> memory) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = {true, true, false},
|
||||
.state = memory::states::Stack,
|
||||
.isSrcMergeDisallowed = true});
|
||||
|
||||
MapInternal(&temp);
|
||||
.isSrcMergeDisallowed = true
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::MapHeapMemory(span<u8> memory) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = {true, true, false},
|
||||
.state = memory::states::Heap});
|
||||
|
||||
MapInternal(&temp);
|
||||
.state = memory::states::Heap
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::MapSharedMemory(span<u8> memory, memory::Permission permission) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = permission,
|
||||
.state = memory::states::SharedMemory,
|
||||
.isSrcMergeDisallowed = true});
|
||||
|
||||
MapInternal(&temp);
|
||||
.isSrcMergeDisallowed = true
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::MapTransferMemory(span<u8> memory, memory::Permission permission) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = permission,
|
||||
.state = permission.raw ? memory::states::TransferMemory : memory::states::TransferMemoryIsolated,
|
||||
.isSrcMergeDisallowed = true});
|
||||
|
||||
MapInternal(&temp);
|
||||
.isSrcMergeDisallowed = true
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::MapThreadLocalMemory(span<u8> memory) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = {true, true, false},
|
||||
.state = memory::states::ThreadLocal});
|
||||
MapInternal(&temp);
|
||||
.state = memory::states::ThreadLocal
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::Reserve(span<u8> memory) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = {false, false, false},
|
||||
.state = memory::states::Reserved});
|
||||
MapInternal(&temp);
|
||||
.state = memory::states::Reserved
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::UnmapMemory(span<u8> memory) {
|
||||
std::unique_lock lock(mutex);
|
||||
std::unique_lock lock{mutex};
|
||||
|
||||
ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) {
|
||||
ForeachChunkinRange(memory, [&](const std::pair<u8 *, ChunkDescriptor> &desc) {
|
||||
if (desc.second.state != memory::states::Unmapped)
|
||||
FreeMemory(span<u8>((u8 *)desc.first, desc.second.size));
|
||||
FreeMemory(span<u8>(desc.first, desc.second.size));
|
||||
});
|
||||
|
||||
std::pair<u8 *, ChunkDescriptor> temp(
|
||||
memory.data(),
|
||||
ChunkDescriptor{
|
||||
MapInternal(std::pair<u8 *, ChunkDescriptor>(
|
||||
memory.data(),{
|
||||
.size = memory.size(),
|
||||
.permission = {false, false, false},
|
||||
.state = memory::states::Unmapped});
|
||||
MapInternal(&temp);
|
||||
.state = memory::states::Unmapped
|
||||
}));
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) void MemoryManager::FreeMemory(span<u8> memory) {
|
||||
@ -535,25 +500,23 @@ namespace skyline::kernel {
|
||||
Logger::Error("Failed to free memory: {}", strerror(errno));
|
||||
}
|
||||
|
||||
void MemoryManager::AddRef(const std::shared_ptr<type::KMemory> &ptr) {
|
||||
memRefs.push_back(ptr);
|
||||
void MemoryManager::AddRef(std::shared_ptr<type::KMemory> ptr) {
|
||||
memRefs.push_back(std::move(ptr));
|
||||
}
|
||||
|
||||
void MemoryManager::RemoveRef(const std::shared_ptr<type::KMemory> &ptr) {
|
||||
std::vector<std::shared_ptr<type::KMemory>>::iterator i{std::find(memRefs.begin(), memRefs.end(), ptr)};
|
||||
void MemoryManager::RemoveRef(std::shared_ptr<type::KMemory> ptr) {
|
||||
auto i = std::find(memRefs.begin(), memRefs.end(), ptr);
|
||||
|
||||
if (*i == ptr) {
|
||||
if (*i == ptr) [[likely]]
|
||||
memRefs.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
size_t MemoryManager::GetUserMemoryUsage() {
|
||||
std::shared_lock lock(mutex);
|
||||
std::shared_lock lock{mutex};
|
||||
size_t size{};
|
||||
|
||||
auto currChunk = upper_bound(heap.data());
|
||||
if (heap.data() < currChunk->first) [[likely]]
|
||||
--currChunk;
|
||||
auto currChunk = chunks.lower_bound(heap.data());
|
||||
|
||||
while (currChunk->first < heap.end().base()) {
|
||||
if (currChunk->second.state == memory::states::Heap)
|
||||
size += currChunk->second.size;
|
||||
@ -564,7 +527,7 @@ namespace skyline::kernel {
|
||||
}
|
||||
|
||||
size_t MemoryManager::GetSystemResourceUsage() {
|
||||
std::shared_lock lock(mutex);
|
||||
std::shared_lock lock{mutex};
|
||||
constexpr size_t KMemoryBlockSize{0x40};
|
||||
return std::min(static_cast<size_t>(state.process->npdm.meta.systemResourceSize), util::AlignUp(chunks.size() * KMemoryBlockSize, constant::PageSize));
|
||||
}
|
||||
|
@ -18,19 +18,19 @@ namespace skyline {
|
||||
/**
|
||||
* @brief Initializes all permissions to false
|
||||
*/
|
||||
constexpr Permission() : raw() {}
|
||||
constexpr Permission() : raw{} {}
|
||||
|
||||
/**
|
||||
* @brief Initializes permissions where the first three bits correspond to RWX
|
||||
*/
|
||||
constexpr explicit Permission(u8 raw) : raw(raw) {}
|
||||
constexpr explicit Permission(u8 raw) : raw{raw} {}
|
||||
|
||||
/**
|
||||
* @param read If memory has read permission
|
||||
* @param write If memory has write permission
|
||||
* @param execute If memory has execute permission
|
||||
*/
|
||||
constexpr Permission(bool read, bool write, bool execute) : r(read), w(write), x(execute) {}
|
||||
constexpr Permission(bool read, bool write, bool execute) : r{read}, w{write}, x{execute} {}
|
||||
|
||||
inline bool operator==(const Permission &rhs) const { return r == rhs.r && w == rhs.w && x == rhs.x; }
|
||||
|
||||
@ -63,13 +63,18 @@ namespace skyline {
|
||||
* @url https://switchbrew.org/wiki/SVC#MemoryAttribute
|
||||
*/
|
||||
union MemoryAttribute {
|
||||
|
||||
constexpr MemoryAttribute() : value{} {}
|
||||
|
||||
constexpr explicit MemoryAttribute(u8 value) : value{value} {}
|
||||
|
||||
struct {
|
||||
bool isBorrowed : 1; //!< This is required for async IPC user buffers
|
||||
bool isIpcLocked : 1; //!< True when IpcRefCount > 0
|
||||
bool isDeviceShared : 1; //!< True when DeviceRefCount > 0
|
||||
bool isUncached : 1; //!< This is used to disable memory caching to share memory with the GPU
|
||||
};
|
||||
u32 value{};
|
||||
u8 value;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -122,9 +127,9 @@ namespace skyline {
|
||||
* @url https://switchbrew.org/wiki/SVC#MemoryState
|
||||
*/
|
||||
union MemoryState {
|
||||
constexpr MemoryState(const u32 value) : value(value) {}
|
||||
constexpr MemoryState(const u32 value) : value{value} {}
|
||||
|
||||
constexpr MemoryState() : value(0) {}
|
||||
constexpr MemoryState() : value{} {}
|
||||
|
||||
constexpr bool operator==(const MemoryState &other) const {
|
||||
return value == other.value;
|
||||
@ -156,7 +161,7 @@ namespace skyline {
|
||||
bool codeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block
|
||||
bool isLinearMapped : 1; //!< If this block is mapped linearly
|
||||
};
|
||||
u32 value{};
|
||||
u32 value;
|
||||
};
|
||||
static_assert(sizeof(MemoryState) == sizeof(u32));
|
||||
|
||||
@ -202,10 +207,10 @@ namespace skyline {
|
||||
namespace kernel {
|
||||
struct ChunkDescriptor {
|
||||
bool isSrcMergeDisallowed;
|
||||
size_t size;
|
||||
memory::Permission permission;
|
||||
memory::MemoryState state;
|
||||
memory::MemoryAttribute attributes;
|
||||
memory::MemoryState state;
|
||||
size_t size;
|
||||
|
||||
constexpr bool IsCompatible(const ChunkDescriptor &chunk) const noexcept {
|
||||
return chunk.permission == permission && chunk.state.value == state.value && chunk.attributes.value == attributes.value && !isSrcMergeDisallowed;
|
||||
@ -222,10 +227,7 @@ namespace skyline {
|
||||
|
||||
std::vector<std::shared_ptr<type::KMemory>> memRefs;
|
||||
|
||||
// Workaround for broken std implementation
|
||||
std::map<u8 *, ChunkDescriptor>::iterator upper_bound(u8 *address);
|
||||
|
||||
void MapInternal(std::pair<u8 *, ChunkDescriptor> *newDesc);
|
||||
void MapInternal(const std::pair<u8 *, ChunkDescriptor> &newDesc);
|
||||
|
||||
void ForeachChunkinRange(span<u8> memory, auto editCallback);
|
||||
|
||||
@ -240,7 +242,7 @@ namespace skyline {
|
||||
span<u8> stack{};
|
||||
span<u8> tlsIo{}; //!< TLS/IO
|
||||
|
||||
size_t setHeapSize; //!< For use by svcSetHeapSize
|
||||
size_t processHeapSize; //!< For use by svcSetHeapSize
|
||||
|
||||
std::shared_mutex mutex; //!< Synchronizes any operations done on the VMM, it's locked in shared mode by readers and exclusive mode by writers
|
||||
|
||||
@ -272,27 +274,27 @@ namespace skyline {
|
||||
span<u8> CreateMirrors(const std::vector<span<u8>> ®ions);
|
||||
|
||||
/**
|
||||
* @brief Sets the attributes for chunks within a certain range
|
||||
* @brief Sets the isBorrowed attribute for chunks within a certain range
|
||||
*/
|
||||
void SetLockOnChunks(span<u8> memory, bool value);
|
||||
|
||||
void SetCPUCachingOnChunks(span<u8> memory, bool value);
|
||||
void SetRegionBorrowed(span<u8> memory, bool value);
|
||||
|
||||
/**
|
||||
* @brief Sets the permission for chunks within a certain range
|
||||
* @brief Sets the isUncached attribute for chunks within a certain range
|
||||
*/
|
||||
void SetRegionCpuCaching(span<u8> memory, bool value);
|
||||
|
||||
/**
|
||||
* @brief Sets the permissions for chunks within a certain range
|
||||
* @note The permissions set here are not accurate to the actual permissions set on the chunk and are only for the guest
|
||||
*/
|
||||
void SetChunkPermission(span<u8> memory, memory::Permission permission);
|
||||
void SetRegionPermission(span<u8> memory, memory::Permission permission);
|
||||
|
||||
/**
|
||||
* @brief Gets the highest chunk's descriptor that contains this address
|
||||
*/
|
||||
std::optional<std::pair<u8 *, ChunkDescriptor>> GetChunk(u8 *addr);
|
||||
|
||||
/**
|
||||
* Various mapping functions for use by the guest
|
||||
* @note UnmapMemory frees the underlying memory as well
|
||||
*/
|
||||
// Various mapping functions for use by the guest
|
||||
void MapCodeMemory(span<u8> memory, memory::Permission permission);
|
||||
|
||||
void MapMutableCodeMemory(span<u8> memory);
|
||||
@ -309,6 +311,9 @@ namespace skyline {
|
||||
|
||||
void Reserve(span<u8> memory);
|
||||
|
||||
/**
|
||||
* @note `UnmapMemory` also calls `FreeMemory` on the unmapped memory range
|
||||
*/
|
||||
void UnmapMemory(span<u8> memory);
|
||||
|
||||
/**
|
||||
@ -318,11 +323,14 @@ namespace skyline {
|
||||
void FreeMemory(span<u8> memory);
|
||||
|
||||
/**
|
||||
* Allows you to add/remove references to shared/transfer memory
|
||||
* @brief Adds a reference to shared memory, extending its lifetime until `RemoveRef` is called
|
||||
*/
|
||||
void AddRef(const std::shared_ptr<type::KMemory> &ptr);
|
||||
void AddRef(std::shared_ptr<type::KMemory> ptr);
|
||||
|
||||
void RemoveRef(const std::shared_ptr<type::KMemory> &ptr);
|
||||
/**
|
||||
* @brief Removes the reference added by `AddRef`
|
||||
*/
|
||||
void RemoveRef(std::shared_ptr<type::KMemory> ptr);
|
||||
|
||||
/**
|
||||
* @return The cumulative size of all heap (Physical Memory + Process Heap) memory mappings, the code region and the main thread stack in bytes
|
||||
@ -347,3 +355,16 @@ namespace skyline {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
template<> struct fmt::formatter<skyline::memory::Permission> {
|
||||
template<typename ParseContext>
|
||||
constexpr auto parse(ParseContext& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
template<typename FormatContext>
|
||||
constexpr auto format(skyline::memory::Permission const& permission, FormatContext& ctx)
|
||||
{
|
||||
return fmt::format_to(ctx.out(), "{}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
}
|
||||
};
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace skyline::kernel::svc {
|
||||
void SetHeapSize(const DeviceState &state) {
|
||||
u64 size{state.ctx->gpr.w1};
|
||||
u32 size{state.ctx->gpr.w1};
|
||||
|
||||
if (!util::IsAligned(size, 0x200000)) [[unlikely]] {
|
||||
state.ctx->gpr.w0 = result::InvalidSize;
|
||||
@ -27,7 +27,7 @@ namespace skyline::kernel::svc {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t heapCurrSize{state.process->memory.setHeapSize};
|
||||
size_t heapCurrSize{state.process->memory.processHeapSize};
|
||||
u8 *heapBaseAddr{state.process->memory.heap.data()};
|
||||
|
||||
if (heapCurrSize < size)
|
||||
@ -35,7 +35,7 @@ namespace skyline::kernel::svc {
|
||||
else if (size < heapCurrSize)
|
||||
state.process->memory.UnmapMemory(span<u8>{heapBaseAddr + size, heapCurrSize - size});
|
||||
|
||||
state.process->memory.setHeapSize = size;
|
||||
state.process->memory.processHeapSize = size;
|
||||
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
state.ctx->gpr.x1 = reinterpret_cast<u64>(heapBaseAddr);
|
||||
@ -67,7 +67,7 @@ namespace skyline::kernel::svc {
|
||||
memory::Permission newPermission(static_cast<u8>(state.ctx->gpr.w2));
|
||||
if ((!newPermission.r && newPermission.w) || newPermission.x) [[unlikely]] {
|
||||
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
|
||||
Logger::Warn("'permission' invalid: {}{}{}", newPermission.r ? 'R' : '-', newPermission.w ? 'W' : '-', newPermission.x ? 'X' : '-');
|
||||
Logger::Warn("'permission' invalid: {}", newPermission);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ namespace skyline::kernel::svc {
|
||||
return;
|
||||
}
|
||||
|
||||
state.process->memory.SetChunkPermission(span<u8>(address, size), newPermission);
|
||||
state.process->memory.SetRegionPermission(span<u8>(address, size), newPermission);
|
||||
|
||||
Logger::Debug("Set permission to {}{}{} at 0x{:X} - 0x{:X} (0x{:X} bytes)", newPermission.r ? 'R' : '-', newPermission.w ? 'W' : '-', newPermission.x ? 'X' : '-', address, address + size, size);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
@ -105,8 +105,8 @@ namespace skyline::kernel::svc {
|
||||
return;
|
||||
}
|
||||
|
||||
memory::MemoryAttribute mask{.value = state.ctx->gpr.w2};
|
||||
memory::MemoryAttribute value{.value = state.ctx->gpr.w3};
|
||||
memory::MemoryAttribute mask{static_cast<u8>(state.ctx->gpr.w2)};
|
||||
memory::MemoryAttribute value{static_cast<u8>(state.ctx->gpr.w3)};
|
||||
|
||||
auto maskedValue{mask.value | value.value};
|
||||
if (maskedValue != mask.value || !mask.isUncached || mask.isDeviceShared || mask.isBorrowed || mask.isIpcLocked) [[unlikely]] {
|
||||
@ -124,7 +124,7 @@ namespace skyline::kernel::svc {
|
||||
return;
|
||||
}
|
||||
|
||||
state.process->memory.SetCPUCachingOnChunks(span<u8>{address, size}, value.isUncached);
|
||||
state.process->memory.SetRegionCpuCaching(span<u8>{address, size}, value.isUncached);
|
||||
|
||||
Logger::Debug("Set CPU caching to {} at 0x{:X} - 0x{:X} (0x{:X} bytes)", static_cast<bool>(value.isUncached), address, address + size, size);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
@ -175,8 +175,8 @@ namespace skyline::kernel::svc {
|
||||
state.process->memory.MapStackMemory(span<u8>{destination, size});
|
||||
std::memcpy(destination, source, size);
|
||||
|
||||
state.process->memory.SetChunkPermission(span<u8>{source, size}, {false, false, false});
|
||||
state.process->memory.SetLockOnChunks(span<u8>{source, size}, true);
|
||||
state.process->memory.SetRegionPermission(span<u8>{source, size}, {false, false, false});
|
||||
state.process->memory.SetRegionBorrowed(span<u8>{source, size}, true);
|
||||
|
||||
Logger::Debug("Mapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes)", source, source + size, destination, destination + size, size);
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
@ -210,8 +210,8 @@ namespace skyline::kernel::svc {
|
||||
dstChunk = state.process->memory.GetChunk(dstChunk.first + dstChunk.second.size).value();
|
||||
|
||||
if ((destination + size) > dstChunk.first) [[likely]] {
|
||||
state.process->memory.SetChunkPermission(span<u8>{source + (dstChunk.first - destination), dstChunk.second.size}, dstChunk.second.permission);
|
||||
state.process->memory.SetLockOnChunks(span<u8>{source + (dstChunk.first - destination), dstChunk.second.size}, false);
|
||||
state.process->memory.SetRegionPermission(span<u8>{source + (dstChunk.first - destination), dstChunk.second.size}, dstChunk.second.permission);
|
||||
state.process->memory.SetRegionBorrowed(span<u8>{source + (dstChunk.first - destination), dstChunk.second.size}, false);
|
||||
|
||||
std::memcpy(source + (dstChunk.first - destination), dstChunk.first, dstChunk.second.size);
|
||||
|
||||
@ -239,7 +239,7 @@ namespace skyline::kernel::svc {
|
||||
.ipcRefCount = 0,
|
||||
};
|
||||
|
||||
Logger::Debug("Address: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Attributes: 0x{:X}, Permissions: {}{}{}", address, memInfo.address, memInfo.size, memInfo.type, memInfo.attributes, chunk->second.permission.r ? 'R' : '-', chunk->second.permission.w ? 'W' : '-', chunk->second.permission.x ? 'X' : '-');
|
||||
Logger::Debug("Address: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Attributes: 0x{:X}, Permissions: {}", address, memInfo.address, memInfo.size, memInfo.type, memInfo.attributes, chunk->second.permission);
|
||||
} else {
|
||||
u64 addressSpaceEnd{reinterpret_cast<u64>(state.process->memory.addressSpace.end().base())};
|
||||
|
||||
@ -254,7 +254,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
*reinterpret_cast<memory::MemoryInfo *>(state.ctx->gpr.x0) = memInfo;
|
||||
// The page info, which is always 0
|
||||
state.ctx->gpr.x1 = 0;
|
||||
state.ctx->gpr.w1 = 0;
|
||||
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
}
|
||||
@ -537,7 +537,7 @@ namespace skyline::kernel::svc {
|
||||
memory::Permission permission(static_cast<u8>(state.ctx->gpr.w3));
|
||||
if ((!permission.r && !permission.w && !permission.x) || (permission.w && !permission.r) || permission.x) [[unlikely]] {
|
||||
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
|
||||
Logger::Warn("'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
Logger::Warn("'permission' invalid: {}", permission);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -613,7 +613,7 @@ namespace skyline::kernel::svc {
|
||||
|
||||
memory::Permission permission(static_cast<u8>(state.ctx->gpr.w3));
|
||||
if ((permission.w && !permission.r) || permission.x) [[unlikely]] {
|
||||
Logger::Warn("'permission' invalid: {}{}{}", permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-');
|
||||
Logger::Warn("'permission' invalid: {}", permission);
|
||||
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
|
||||
return;
|
||||
}
|
||||
|
@ -8,12 +8,12 @@
|
||||
#include "KProcess.h"
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KMemory::KMemory(const DeviceState &state, KType objectType, size_t size) : KObject(state, objectType), guest() {
|
||||
fd = ASharedMemory_create(objectType == KType::KSharedMemory ? "HOS-KSharedMemory" : "HOS-KTransferMemory", size);
|
||||
if (fd < 0) [[unlikely]]
|
||||
throw exception("An error occurred while creating shared memory: {}", fd);
|
||||
KMemory::KMemory(const DeviceState &state, KType objectType, size_t size) : KObject{state, objectType}, guest{} {
|
||||
fileDescriptor = ASharedMemory_create(objectType == KType::KSharedMemory ? "HOS-KSharedMemory" : "HOS-KTransferMemory", size);
|
||||
if (fileDescriptor < 0) [[unlikely]]
|
||||
throw exception("An error occurred while creating shared memory: {}", fileDescriptor);
|
||||
|
||||
u8 *hostPtr{static_cast<u8 *>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))};
|
||||
u8 *hostPtr{static_cast<u8 *>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0))};
|
||||
if (hostPtr == MAP_FAILED) [[unlikely]]
|
||||
throw exception("An occurred while mapping shared memory: {}", strerror(errno));
|
||||
|
||||
@ -28,7 +28,7 @@ namespace skyline::kernel::type {
|
||||
if (guest.valid()) [[unlikely]]
|
||||
throw exception("Mapping KMemory multiple times on guest is not supported: Requested Mapping: 0x{:X} - 0x{:X} (0x{:X}), Current Mapping: 0x{:X} - 0x{:X} (0x{:X})", map.data(), map.end().base(), map.size(), guest.data(), guest.end().base(), guest.size());
|
||||
|
||||
if (mmap(map.data(), map.size(), permission.Get() ? PROT_READ | PROT_WRITE : PROT_NONE, MAP_SHARED | (map.data() ? MAP_FIXED : 0), fd, 0) == MAP_FAILED) [[unlikely]]
|
||||
if (mmap(map.data(), map.size(), permission.Get() ? PROT_READ | PROT_WRITE : PROT_NONE, MAP_SHARED | (map.data() ? MAP_FIXED : 0), fileDescriptor, 0) == MAP_FAILED) [[unlikely]]
|
||||
throw exception("An error occurred while mapping shared memory in guest: {}", strerror(errno));
|
||||
guest = map;
|
||||
|
||||
@ -51,6 +51,6 @@ namespace skyline::kernel::type {
|
||||
if (host.valid())
|
||||
munmap(host.data(), host.size());
|
||||
|
||||
close(fd);
|
||||
close(fileDescriptor);
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ namespace skyline::kernel::type {
|
||||
*/
|
||||
class KMemory : public KObject {
|
||||
private:
|
||||
int fd; //!< A file descriptor to the underlying shared memory
|
||||
int fileDescriptor; //!< A file descriptor to the underlying shared memory
|
||||
|
||||
public:
|
||||
KMemory(const DeviceState &state, KType objectType, size_t size);
|
||||
|
@ -50,7 +50,7 @@ namespace skyline::kernel::type {
|
||||
void KProcess::InitializeHeapTls() {
|
||||
constexpr size_t DefaultHeapSize{0x200000};
|
||||
memory.MapHeapMemory(span<u8>{state.process->memory.heap.data(), DefaultHeapSize});
|
||||
memory.setHeapSize = DefaultHeapSize;
|
||||
memory.processHeapSize = DefaultHeapSize;
|
||||
tlsExceptionContext = AllocateTlsSlot();
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KSharedMemory::KSharedMemory(const DeviceState &state, size_t size)
|
||||
: KMemory(state, KType::KSharedMemory, size) {}
|
||||
: KMemory{state, KType::KSharedMemory, size} {}
|
||||
|
||||
u8 *KSharedMemory::Map(span<u8> map, memory::Permission permission) {
|
||||
u8 *result{KMemory::Map(map, permission)};
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace skyline::kernel::type {
|
||||
KTransferMemory::KTransferMemory(const DeviceState &state, size_t size)
|
||||
: KMemory(state, KType::KTransferMemory, size) {}
|
||||
: KMemory{state, KType::KTransferMemory, size} {}
|
||||
|
||||
u8 *KTransferMemory::Map(span<u8> map, memory::Permission permission) {
|
||||
std::memcpy(host.data(), map.data(), map.size());
|
||||
@ -21,7 +21,7 @@ namespace skyline::kernel::type {
|
||||
return nullptr;
|
||||
} else {
|
||||
state.process->memory.MapTransferMemory(guest, permission);
|
||||
state.process->memory.SetLockOnChunks(guest, true);
|
||||
state.process->memory.SetRegionBorrowed(guest, true);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ namespace skyline::loader {
|
||||
|
||||
if (process->memory.addressSpaceType == memory::AddressSpaceType::AddressSpace36Bit) {
|
||||
process->memory.MapHeapMemory(span<u8>{base, patch.size + hookSize}); // ---
|
||||
process->memory.SetChunkPermission(span<u8>{base, patch.size + hookSize}, memory::Permission{false, false, false});
|
||||
process->memory.SetRegionPermission(span<u8>{base, patch.size + hookSize}, memory::Permission{false, false, false});
|
||||
} else {
|
||||
process->memory.Reserve(span<u8>{base, patch.size + hookSize}); // ---
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user