General memman fixups & address review

This commit is contained in:
TheASVigilante 2023-05-05 18:15:47 +02:00
parent 1513e5f6df
commit 850f616dc7
9 changed files with 202 additions and 218 deletions

View File

@ -7,46 +7,36 @@
#include "types/KProcess.h" #include "types/KProcess.h"
namespace skyline::kernel { 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 { MemoryManager::~MemoryManager() noexcept {
if (base.valid() && !base.empty()) if (base.valid() && !base.empty())
munmap(reinterpret_cast<void *>(base.data()), base.size()); 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) { void MemoryManager::MapInternal(const std::pair<u8 *, ChunkDescriptor> &newDesc) {
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) {
// The chunk that contains / precedes the new chunk base address // The chunk that contains / precedes the new chunk base address
auto firstChunkBase{upper_bound(newDesc->first)}; auto firstChunkBase{chunks.lower_bound(newDesc.first)};
while (newDesc->first <= firstChunkBase->first) if (newDesc.first <= firstChunkBase->first)
--firstChunkBase; --firstChunkBase;
// The chunk that contains / follows the end address of the new chunk // The chunk that contains / follows the end address of the new chunk
auto lastChunkBase{upper_bound(newDesc->first + newDesc->second.size)}; auto lastChunkBase{chunks.lower_bound(newDesc.first + newDesc.second.size)};
while ((newDesc->first + newDesc->second.size) < lastChunkBase->first) if ((newDesc.first + newDesc.second.size) < lastChunkBase->first)
--lastChunkBase; --lastChunkBase;
ChunkDescriptor firstChunk{firstChunkBase->second}; ChunkDescriptor firstChunk{firstChunkBase->second};
ChunkDescriptor lastChunk{lastChunkBase->second}; ChunkDescriptor lastChunk{lastChunkBase->second};
bool needsReprotection{false}; 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 // We cut a hole in a single chunk
if (firstChunkBase->first == lastChunkBase->first) { if (firstChunkBase->first == lastChunkBase->first) {
if (firstChunk.IsCompatible(newDesc->second)) [[unlikely]] if (firstChunk.IsCompatible(newDesc.second)) [[unlikely]]
// No editing necessary // No editing necessary
return; return;
@ -54,15 +44,15 @@ namespace skyline::kernel {
needsReprotection = true; needsReprotection = true;
// We edit the chunk's first half // 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; chunks[firstChunkBase->first] = firstChunk;
// We create the chunk's second half // We create the chunk's second half
lastChunk.size = static_cast<size_t>((lastChunkBase->first + lastChunk.size) - (newDesc->first + newDesc->second.size)); lastChunk.size = static_cast<size_t>((lastChunkBase->first + lastChunk.size) - (newDesc.first + newDesc.second.size));
chunks[newDesc->first + newDesc->second.size] = lastChunk; chunks.insert({newDesc.first + newDesc.second.size, lastChunk});
// Insert new chunk in between // Insert new chunk in between
chunks[newDesc->first] = newDesc->second; chunks.insert(newDesc);
} else { } else {
// If there are descriptors between first and last chunk, delete them // If there are descriptors between first and last chunk, delete them
if ((firstChunkBase->first + firstChunk.size) != lastChunkBase->first) { if ((firstChunkBase->first + firstChunk.size) != lastChunkBase->first) {
@ -79,13 +69,13 @@ namespace skyline::kernel {
bool shouldInsert{true}; bool shouldInsert{true};
if (firstChunk.IsCompatible(newDesc->second)) { if (firstChunk.IsCompatible(newDesc.second)) {
shouldInsert = false; 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; chunks[firstChunkBase->first] = firstChunk;
} else if ((firstChunkBase->first + firstChunk.size) != newDesc->first) { } else if ((firstChunkBase->first + firstChunk.size) != newDesc.first) {
firstChunk.size = static_cast<size_t>(newDesc->first - firstChunkBase->first); firstChunk.size = static_cast<size_t>(newDesc.first - firstChunkBase->first);
chunks[firstChunkBase->first] = firstChunk; chunks[firstChunkBase->first] = firstChunk;
@ -93,25 +83,25 @@ namespace skyline::kernel {
needsReprotection = true; needsReprotection = true;
} }
if (lastChunk.IsCompatible(newDesc->second)) { if (lastChunk.IsCompatible(newDesc.second)) {
u8 *oldBase{lastChunkBase->first}; u8 *oldBase{lastChunkBase->first};
chunks.erase(lastChunkBase); chunks.erase(lastChunkBase);
if (shouldInsert) { if (shouldInsert) {
shouldInsert = false; 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 { } else {
firstChunk.size = static_cast<size_t>((lastChunk.size + oldBase) - firstChunkBase->first); firstChunk.size = static_cast<size_t>((lastChunk.size + oldBase) - firstChunkBase->first);
chunks[firstChunkBase->first] = firstChunk; chunks[firstChunkBase->first] = firstChunk;
} }
} else if ((newDesc->first + newDesc->second.size) != lastChunkBase->first) { } else if ((newDesc.first + newDesc.second.size) != lastChunkBase->first) {
lastChunk.size = static_cast<size_t>((lastChunk.size + lastChunkBase->first) - (newDesc->first + newDesc->second.size)); lastChunk.size = static_cast<size_t>((lastChunk.size + lastChunkBase->first) - (newDesc.first + newDesc.second.size));
chunks.erase(lastChunkBase); chunks.erase(lastChunkBase);
chunks[newDesc->first + newDesc->second.size] = lastChunk; chunks[newDesc.first + newDesc.second.size] = lastChunk;
if ((lastChunk.state == memory::states::Unmapped) != isUnmapping) if ((lastChunk.state == memory::states::Unmapped) != isUnmapping)
needsReprotection = true; needsReprotection = true;
@ -119,49 +109,45 @@ namespace skyline::kernel {
// Insert if not merged // Insert if not merged
if (shouldInsert) if (shouldInsert)
chunks[newDesc->first] = newDesc->second; chunks.insert(newDesc);
} }
if (needsReprotection) 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)); Logger::Warn("Reprotection failed: {}", strerror(errno));
} }
void MemoryManager::ForeachChunkinRange(span<skyline::u8> memory, auto editCallback) { void MemoryManager::ForeachChunkinRange(span<u8> memory, auto editCallback) {
auto chunkBase{upper_bound(memory.data())}; auto chunkBase{chunks.lower_bound(memory.data())};
if (memory.data() < chunkBase->first) if (memory.data() < chunkBase->first)
--chunkBase; --chunkBase;
ChunkDescriptor resultChunk{chunkBase->second};
size_t sizeLeft{memory.size()}; size_t sizeLeft{memory.size()};
if (chunkBase->first < memory.data()) { if (chunkBase->first < memory.data()) [[unlikely]] {
size_t copySize{std::min<size_t>(resultChunk.size - (static_cast<size_t>(memory.data() - chunkBase->first)), memory.size())}; 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); std::pair<u8 *, ChunkDescriptor> temp{memory.data(), chunkBase->second};
temp.second.size = copySize; temp.second.size = chunkSize;
editCallback(temp); editCallback(temp);
++chunkBase; ++chunkBase;
resultChunk = chunkBase->second; sizeLeft -= chunkSize;
sizeLeft -= copySize;
} }
while (sizeLeft) { while (sizeLeft) {
if (sizeLeft < resultChunk.size) { if (sizeLeft < chunkBase->second.size) {
std::pair<u8 *, ChunkDescriptor> temp(chunkBase->first, resultChunk); std::pair<u8 *, ChunkDescriptor> temp(*chunkBase);
temp.second.size = sizeLeft; temp.second.size = sizeLeft;
editCallback(temp); editCallback(temp);
break; break;
} else [[likely]] { } else [[likely]] {
std::pair<u8 *, ChunkDescriptor> temp(chunkBase->first, resultChunk); std::pair<u8 *, ChunkDescriptor> temp(*chunkBase);
editCallback(temp); editCallback(temp);
sizeLeft = sizeLeft - resultChunk.size; sizeLeft = sizeLeft - chunkBase->second.size;
++chunkBase; ++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 // 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}; static constexpr size_t KgslReservedRegionSize{1ULL << 35};
base = AllocateMappedRange(baseSize, RegionAlignment, KgslReservedRegionSize, addressSpace.size(), false);
if (type != memory::AddressSpaceType::AddressSpace36Bit) { 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; code = base;
} else { } else {
codeBase36Bit = AllocateMappedRange(0x78000000, RegionAlignment, 0x8000000, KgslReservedRegionSize, false); code = codeBase36Bit = AllocateMappedRange(0x78000000, RegionAlignment, 0x8000000, KgslReservedRegionSize, false);
base = AllocateMappedRange(baseSize, RegionAlignment, KgslReservedRegionSize, addressSpace.size(), false);
if ((reinterpret_cast<u64>(base.data()) + baseSize) > (1ULL << 36)) { 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}; 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(), .size = addressSpace.size(),
.state = memory::states::Unmapped, .state = memory::states::Unmapped,
}; }}, {reinterpret_cast<u8 *>(UINT64_MAX), {
.state = memory::states::Reserved,
code = codeBase36Bit; }}};
}
} }
void MemoryManager::InitializeRegions(span<u8> codeRegion) { 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 // 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)) { 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), .size = reinterpret_cast<size_t>(codeBase36Bit.data() - 0x8000000),
.state = memory::states::Heap, .state = memory::states::Heap
}); }));
MapInternal(&tmp);
} }
// Place code, stack and TLS/IO in the lower 36-bits of the host AS and heap and alias past that // 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]] 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); 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()); munmap(base.end().base(), newSize - base.size());
break; break;
@ -364,166 +344,151 @@ namespace skyline::kernel {
return span<u8>{reinterpret_cast<u8 *>(mirrorBase), totalSize}; return span<u8>{reinterpret_cast<u8 *>(mirrorBase), totalSize};
} }
void MemoryManager::SetLockOnChunks(span<u8> memory, bool value) { void MemoryManager::SetRegionBorrowed(span<u8> memory, bool value) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) { ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) {
desc.second.attributes.isBorrowed = value; desc.second.attributes.isBorrowed = value;
MapInternal(&desc); MapInternal(desc);
}); });
} }
void MemoryManager::SetCPUCachingOnChunks(span<u8> memory, bool value) { void MemoryManager::SetRegionCpuCaching(span<u8> memory, bool value) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) { ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) {
desc.second.attributes.isUncached = value; desc.second.attributes.isUncached = value;
MapInternal(&desc); MapInternal(desc);
}); });
} }
void MemoryManager::SetChunkPermission(span<u8> memory, memory::Permission permission) { void MemoryManager::SetRegionPermission(span<u8> memory, memory::Permission permission) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) { ForeachChunkinRange(memory, [&](std::pair<u8 *, ChunkDescriptor> &desc) __attribute__((always_inline)) {
desc.second.permission = permission; desc.second.permission = permission;
MapInternal(&desc); MapInternal(desc);
}); });
} }
std::optional<std::pair<u8 *, ChunkDescriptor>> MemoryManager::GetChunk(u8 *addr) { 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]] if (!addressSpace.contains(addr)) [[unlikely]]
return std::nullopt; return std::nullopt;
auto chunkBase = upper_bound(addr); auto chunkBase = chunks.lower_bound(addr);
if (addr < chunkBase->first) [[likely]] if (addr < chunkBase->first)
--chunkBase; --chunkBase;
return std::make_optional(*chunkBase); return std::make_optional(*chunkBase);
} }
__attribute__((always_inline)) void MemoryManager::MapCodeMemory(span<u8> memory, memory::Permission permission) { __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( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = permission, .permission = permission,
.state = memory::states::Code}); .state = memory::states::Code
}));
MapInternal(&temp);
} }
__attribute__((always_inline)) void MemoryManager::MapMutableCodeMemory(span<u8> memory) { __attribute__((always_inline)) void MemoryManager::MapMutableCodeMemory(span<u8> memory) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
std::pair<u8 *, ChunkDescriptor> temp( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = {true, true, false}, .permission = {true, true, false},
.state = memory::states::CodeMutable}); .state = memory::states::CodeMutable
}));
MapInternal(&temp);
} }
__attribute__((always_inline)) void MemoryManager::MapStackMemory(span<u8> memory) { __attribute__((always_inline)) void MemoryManager::MapStackMemory(span<u8> memory) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
std::pair<u8 *, ChunkDescriptor> temp( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = {true, true, false}, .permission = {true, true, false},
.state = memory::states::Stack, .state = memory::states::Stack,
.isSrcMergeDisallowed = true}); .isSrcMergeDisallowed = true
}));
MapInternal(&temp);
} }
__attribute__((always_inline)) void MemoryManager::MapHeapMemory(span<u8> memory) { __attribute__((always_inline)) void MemoryManager::MapHeapMemory(span<u8> memory) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
std::pair<u8 *, ChunkDescriptor> temp( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = {true, true, false}, .permission = {true, true, false},
.state = memory::states::Heap}); .state = memory::states::Heap
}));
MapInternal(&temp);
} }
__attribute__((always_inline)) void MemoryManager::MapSharedMemory(span<u8> memory, memory::Permission permission) { __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( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = permission, .permission = permission,
.state = memory::states::SharedMemory, .state = memory::states::SharedMemory,
.isSrcMergeDisallowed = true}); .isSrcMergeDisallowed = true
}));
MapInternal(&temp);
} }
__attribute__((always_inline)) void MemoryManager::MapTransferMemory(span<u8> memory, memory::Permission permission) { __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( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = permission, .permission = permission,
.state = permission.raw ? memory::states::TransferMemory : memory::states::TransferMemoryIsolated, .state = permission.raw ? memory::states::TransferMemory : memory::states::TransferMemoryIsolated,
.isSrcMergeDisallowed = true}); .isSrcMergeDisallowed = true
}));
MapInternal(&temp);
} }
__attribute__((always_inline)) void MemoryManager::MapThreadLocalMemory(span<u8> memory) { __attribute__((always_inline)) void MemoryManager::MapThreadLocalMemory(span<u8> memory) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
std::pair<u8 *, ChunkDescriptor> temp( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = {true, true, false}, .permission = {true, true, false},
.state = memory::states::ThreadLocal}); .state = memory::states::ThreadLocal
MapInternal(&temp); }));
} }
__attribute__((always_inline)) void MemoryManager::Reserve(span<u8> memory) { __attribute__((always_inline)) void MemoryManager::Reserve(span<u8> memory) {
std::unique_lock lock(mutex); std::unique_lock lock{mutex};
std::pair<u8 *, ChunkDescriptor> temp( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = {false, false, false}, .permission = {false, false, false},
.state = memory::states::Reserved}); .state = memory::states::Reserved
MapInternal(&temp); }));
} }
__attribute__((always_inline)) void MemoryManager::UnmapMemory(span<u8> memory) { __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) 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( MapInternal(std::pair<u8 *, ChunkDescriptor>(
memory.data(), memory.data(),{
ChunkDescriptor{
.size = memory.size(), .size = memory.size(),
.permission = {false, false, false}, .permission = {false, false, false},
.state = memory::states::Unmapped}); .state = memory::states::Unmapped
MapInternal(&temp); }));
} }
__attribute__((always_inline)) void MemoryManager::FreeMemory(span<u8> memory) { __attribute__((always_inline)) void MemoryManager::FreeMemory(span<u8> memory) {
@ -535,25 +500,23 @@ namespace skyline::kernel {
Logger::Error("Failed to free memory: {}", strerror(errno)); Logger::Error("Failed to free memory: {}", strerror(errno));
} }
void MemoryManager::AddRef(const std::shared_ptr<type::KMemory> &ptr) { void MemoryManager::AddRef(std::shared_ptr<type::KMemory> ptr) {
memRefs.push_back(ptr); memRefs.push_back(std::move(ptr));
} }
void MemoryManager::RemoveRef(const std::shared_ptr<type::KMemory> &ptr) { void MemoryManager::RemoveRef(std::shared_ptr<type::KMemory> ptr) {
std::vector<std::shared_ptr<type::KMemory>>::iterator i{std::find(memRefs.begin(), memRefs.end(), ptr)}; auto i = std::find(memRefs.begin(), memRefs.end(), ptr);
if (*i == ptr) { if (*i == ptr) [[likely]]
memRefs.erase(i); memRefs.erase(i);
} }
}
size_t MemoryManager::GetUserMemoryUsage() { size_t MemoryManager::GetUserMemoryUsage() {
std::shared_lock lock(mutex); std::shared_lock lock{mutex};
size_t size{}; size_t size{};
auto currChunk = upper_bound(heap.data()); auto currChunk = chunks.lower_bound(heap.data());
if (heap.data() < currChunk->first) [[likely]]
--currChunk;
while (currChunk->first < heap.end().base()) { while (currChunk->first < heap.end().base()) {
if (currChunk->second.state == memory::states::Heap) if (currChunk->second.state == memory::states::Heap)
size += currChunk->second.size; size += currChunk->second.size;
@ -564,7 +527,7 @@ namespace skyline::kernel {
} }
size_t MemoryManager::GetSystemResourceUsage() { size_t MemoryManager::GetSystemResourceUsage() {
std::shared_lock lock(mutex); std::shared_lock lock{mutex};
constexpr size_t KMemoryBlockSize{0x40}; constexpr size_t KMemoryBlockSize{0x40};
return std::min(static_cast<size_t>(state.process->npdm.meta.systemResourceSize), util::AlignUp(chunks.size() * KMemoryBlockSize, constant::PageSize)); return std::min(static_cast<size_t>(state.process->npdm.meta.systemResourceSize), util::AlignUp(chunks.size() * KMemoryBlockSize, constant::PageSize));
} }

View File

@ -18,19 +18,19 @@ namespace skyline {
/** /**
* @brief Initializes all permissions to false * @brief Initializes all permissions to false
*/ */
constexpr Permission() : raw() {} constexpr Permission() : raw{} {}
/** /**
* @brief Initializes permissions where the first three bits correspond to RWX * @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 read If memory has read permission
* @param write If memory has write permission * @param write If memory has write permission
* @param execute If memory has execute 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; } 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 * @url https://switchbrew.org/wiki/SVC#MemoryAttribute
*/ */
union MemoryAttribute { union MemoryAttribute {
constexpr MemoryAttribute() : value{} {}
constexpr explicit MemoryAttribute(u8 value) : value{value} {}
struct { struct {
bool isBorrowed : 1; //!< This is required for async IPC user buffers bool isBorrowed : 1; //!< This is required for async IPC user buffers
bool isIpcLocked : 1; //!< True when IpcRefCount > 0 bool isIpcLocked : 1; //!< True when IpcRefCount > 0
bool isDeviceShared : 1; //!< True when DeviceRefCount > 0 bool isDeviceShared : 1; //!< True when DeviceRefCount > 0
bool isUncached : 1; //!< This is used to disable memory caching to share memory with the GPU 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 * @url https://switchbrew.org/wiki/SVC#MemoryState
*/ */
union 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 { constexpr bool operator==(const MemoryState &other) const {
return value == other.value; return value == other.value;
@ -156,7 +161,7 @@ namespace skyline {
bool codeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block bool codeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block
bool isLinearMapped : 1; //!< If this block is mapped linearly bool isLinearMapped : 1; //!< If this block is mapped linearly
}; };
u32 value{}; u32 value;
}; };
static_assert(sizeof(MemoryState) == sizeof(u32)); static_assert(sizeof(MemoryState) == sizeof(u32));
@ -202,10 +207,10 @@ namespace skyline {
namespace kernel { namespace kernel {
struct ChunkDescriptor { struct ChunkDescriptor {
bool isSrcMergeDisallowed; bool isSrcMergeDisallowed;
size_t size;
memory::Permission permission; memory::Permission permission;
memory::MemoryState state;
memory::MemoryAttribute attributes; memory::MemoryAttribute attributes;
memory::MemoryState state;
size_t size;
constexpr bool IsCompatible(const ChunkDescriptor &chunk) const noexcept { constexpr bool IsCompatible(const ChunkDescriptor &chunk) const noexcept {
return chunk.permission == permission && chunk.state.value == state.value && chunk.attributes.value == attributes.value && !isSrcMergeDisallowed; 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; std::vector<std::shared_ptr<type::KMemory>> memRefs;
// Workaround for broken std implementation void MapInternal(const std::pair<u8 *, ChunkDescriptor> &newDesc);
std::map<u8 *, ChunkDescriptor>::iterator upper_bound(u8 *address);
void MapInternal(std::pair<u8 *, ChunkDescriptor> *newDesc);
void ForeachChunkinRange(span<u8> memory, auto editCallback); void ForeachChunkinRange(span<u8> memory, auto editCallback);
@ -240,7 +242,7 @@ namespace skyline {
span<u8> stack{}; span<u8> stack{};
span<u8> tlsIo{}; //!< TLS/IO 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 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>> &regions); span<u8> CreateMirrors(const std::vector<span<u8>> &regions);
/** /**
* @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 SetRegionBorrowed(span<u8> memory, bool value);
void SetCPUCachingOnChunks(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 * @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 * @brief Gets the highest chunk's descriptor that contains this address
*/ */
std::optional<std::pair<u8 *, ChunkDescriptor>> GetChunk(u8 *addr); std::optional<std::pair<u8 *, ChunkDescriptor>> GetChunk(u8 *addr);
/** // Various mapping functions for use by the guest
* Various mapping functions for use by the guest
* @note UnmapMemory frees the underlying memory as well
*/
void MapCodeMemory(span<u8> memory, memory::Permission permission); void MapCodeMemory(span<u8> memory, memory::Permission permission);
void MapMutableCodeMemory(span<u8> memory); void MapMutableCodeMemory(span<u8> memory);
@ -309,6 +311,9 @@ namespace skyline {
void Reserve(span<u8> memory); void Reserve(span<u8> memory);
/**
* @note `UnmapMemory` also calls `FreeMemory` on the unmapped memory range
*/
void UnmapMemory(span<u8> memory); void UnmapMemory(span<u8> memory);
/** /**
@ -318,11 +323,14 @@ namespace skyline {
void FreeMemory(span<u8> memory); 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 * @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' : '-');
}
};

View File

@ -11,7 +11,7 @@
namespace skyline::kernel::svc { namespace skyline::kernel::svc {
void SetHeapSize(const DeviceState &state) { void SetHeapSize(const DeviceState &state) {
u64 size{state.ctx->gpr.w1}; u32 size{state.ctx->gpr.w1};
if (!util::IsAligned(size, 0x200000)) [[unlikely]] { if (!util::IsAligned(size, 0x200000)) [[unlikely]] {
state.ctx->gpr.w0 = result::InvalidSize; state.ctx->gpr.w0 = result::InvalidSize;
@ -27,7 +27,7 @@ namespace skyline::kernel::svc {
return; return;
} }
size_t heapCurrSize{state.process->memory.setHeapSize}; size_t heapCurrSize{state.process->memory.processHeapSize};
u8 *heapBaseAddr{state.process->memory.heap.data()}; u8 *heapBaseAddr{state.process->memory.heap.data()};
if (heapCurrSize < size) if (heapCurrSize < size)
@ -35,7 +35,7 @@ namespace skyline::kernel::svc {
else if (size < heapCurrSize) else if (size < heapCurrSize)
state.process->memory.UnmapMemory(span<u8>{heapBaseAddr + size, heapCurrSize - size}); 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.w0 = Result{};
state.ctx->gpr.x1 = reinterpret_cast<u64>(heapBaseAddr); 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)); memory::Permission newPermission(static_cast<u8>(state.ctx->gpr.w2));
if ((!newPermission.r && newPermission.w) || newPermission.x) [[unlikely]] { if ((!newPermission.r && newPermission.w) || newPermission.x) [[unlikely]] {
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission; 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; return;
} }
@ -78,7 +78,7 @@ namespace skyline::kernel::svc {
return; 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); 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{}; state.ctx->gpr.w0 = Result{};
@ -105,8 +105,8 @@ namespace skyline::kernel::svc {
return; return;
} }
memory::MemoryAttribute mask{.value = state.ctx->gpr.w2}; memory::MemoryAttribute mask{static_cast<u8>(state.ctx->gpr.w2)};
memory::MemoryAttribute value{.value = state.ctx->gpr.w3}; memory::MemoryAttribute value{static_cast<u8>(state.ctx->gpr.w3)};
auto maskedValue{mask.value | value.value}; auto maskedValue{mask.value | value.value};
if (maskedValue != mask.value || !mask.isUncached || mask.isDeviceShared || mask.isBorrowed || mask.isIpcLocked) [[unlikely]] { if (maskedValue != mask.value || !mask.isUncached || mask.isDeviceShared || mask.isBorrowed || mask.isIpcLocked) [[unlikely]] {
@ -124,7 +124,7 @@ namespace skyline::kernel::svc {
return; 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); 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{}; state.ctx->gpr.w0 = Result{};
@ -175,8 +175,8 @@ namespace skyline::kernel::svc {
state.process->memory.MapStackMemory(span<u8>{destination, size}); state.process->memory.MapStackMemory(span<u8>{destination, size});
std::memcpy(destination, source, size); std::memcpy(destination, source, size);
state.process->memory.SetChunkPermission(span<u8>{source, size}, {false, false, false}); state.process->memory.SetRegionPermission(span<u8>{source, size}, {false, false, false});
state.process->memory.SetLockOnChunks(span<u8>{source, size}, true); 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); 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{}; state.ctx->gpr.w0 = Result{};
@ -210,8 +210,8 @@ namespace skyline::kernel::svc {
dstChunk = state.process->memory.GetChunk(dstChunk.first + dstChunk.second.size).value(); dstChunk = state.process->memory.GetChunk(dstChunk.first + dstChunk.second.size).value();
if ((destination + size) > dstChunk.first) [[likely]] { 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.SetRegionPermission(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.SetRegionBorrowed(span<u8>{source + (dstChunk.first - destination), dstChunk.second.size}, false);
std::memcpy(source + (dstChunk.first - destination), dstChunk.first, dstChunk.second.size); std::memcpy(source + (dstChunk.first - destination), dstChunk.first, dstChunk.second.size);
@ -239,7 +239,7 @@ namespace skyline::kernel::svc {
.ipcRefCount = 0, .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 { } else {
u64 addressSpaceEnd{reinterpret_cast<u64>(state.process->memory.addressSpace.end().base())}; 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; *reinterpret_cast<memory::MemoryInfo *>(state.ctx->gpr.x0) = memInfo;
// The page info, which is always 0 // The page info, which is always 0
state.ctx->gpr.x1 = 0; state.ctx->gpr.w1 = 0;
state.ctx->gpr.w0 = Result{}; state.ctx->gpr.w0 = Result{};
} }
@ -537,7 +537,7 @@ namespace skyline::kernel::svc {
memory::Permission permission(static_cast<u8>(state.ctx->gpr.w3)); memory::Permission permission(static_cast<u8>(state.ctx->gpr.w3));
if ((!permission.r && !permission.w && !permission.x) || (permission.w && !permission.r) || permission.x) [[unlikely]] { if ((!permission.r && !permission.w && !permission.x) || (permission.w && !permission.r) || permission.x) [[unlikely]] {
state.ctx->gpr.w0 = result::InvalidNewMemoryPermission; 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; return;
} }
@ -613,7 +613,7 @@ namespace skyline::kernel::svc {
memory::Permission permission(static_cast<u8>(state.ctx->gpr.w3)); memory::Permission permission(static_cast<u8>(state.ctx->gpr.w3));
if ((permission.w && !permission.r) || permission.x) [[unlikely]] { 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; state.ctx->gpr.w0 = result::InvalidNewMemoryPermission;
return; return;
} }

View File

@ -8,12 +8,12 @@
#include "KProcess.h" #include "KProcess.h"
namespace skyline::kernel::type { namespace skyline::kernel::type {
KMemory::KMemory(const DeviceState &state, KType objectType, size_t size) : KObject(state, objectType), guest() { 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); fileDescriptor = ASharedMemory_create(objectType == KType::KSharedMemory ? "HOS-KSharedMemory" : "HOS-KTransferMemory", size);
if (fd < 0) [[unlikely]] if (fileDescriptor < 0) [[unlikely]]
throw exception("An error occurred while creating shared memory: {}", fd); 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]] if (hostPtr == MAP_FAILED) [[unlikely]]
throw exception("An occurred while mapping shared memory: {}", strerror(errno)); throw exception("An occurred while mapping shared memory: {}", strerror(errno));
@ -28,7 +28,7 @@ namespace skyline::kernel::type {
if (guest.valid()) [[unlikely]] 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()); 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)); throw exception("An error occurred while mapping shared memory in guest: {}", strerror(errno));
guest = map; guest = map;
@ -51,6 +51,6 @@ namespace skyline::kernel::type {
if (host.valid()) if (host.valid())
munmap(host.data(), host.size()); munmap(host.data(), host.size());
close(fd); close(fileDescriptor);
} }
} }

View File

@ -12,7 +12,7 @@ namespace skyline::kernel::type {
*/ */
class KMemory : public KObject { class KMemory : public KObject {
private: private:
int fd; //!< A file descriptor to the underlying shared memory int fileDescriptor; //!< A file descriptor to the underlying shared memory
public: public:
KMemory(const DeviceState &state, KType objectType, size_t size); KMemory(const DeviceState &state, KType objectType, size_t size);

View File

@ -50,7 +50,7 @@ namespace skyline::kernel::type {
void KProcess::InitializeHeapTls() { void KProcess::InitializeHeapTls() {
constexpr size_t DefaultHeapSize{0x200000}; constexpr size_t DefaultHeapSize{0x200000};
memory.MapHeapMemory(span<u8>{state.process->memory.heap.data(), DefaultHeapSize}); memory.MapHeapMemory(span<u8>{state.process->memory.heap.data(), DefaultHeapSize});
memory.setHeapSize = DefaultHeapSize; memory.processHeapSize = DefaultHeapSize;
tlsExceptionContext = AllocateTlsSlot(); tlsExceptionContext = AllocateTlsSlot();
} }

View File

@ -6,7 +6,7 @@
namespace skyline::kernel::type { namespace skyline::kernel::type {
KSharedMemory::KSharedMemory(const DeviceState &state, size_t size) 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 *KSharedMemory::Map(span<u8> map, memory::Permission permission) {
u8 *result{KMemory::Map(map, permission)}; u8 *result{KMemory::Map(map, permission)};

View File

@ -6,7 +6,7 @@
namespace skyline::kernel::type { namespace skyline::kernel::type {
KTransferMemory::KTransferMemory(const DeviceState &state, size_t size) 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) { u8 *KTransferMemory::Map(span<u8> map, memory::Permission permission) {
std::memcpy(host.data(), map.data(), map.size()); std::memcpy(host.data(), map.data(), map.size());
@ -21,7 +21,7 @@ namespace skyline::kernel::type {
return nullptr; return nullptr;
} else { } else {
state.process->memory.MapTransferMemory(guest, permission); state.process->memory.MapTransferMemory(guest, permission);
state.process->memory.SetLockOnChunks(guest, true); state.process->memory.SetRegionBorrowed(guest, true);
return result; return result;
} }
} }

View File

@ -91,7 +91,7 @@ namespace skyline::loader {
if (process->memory.addressSpaceType == memory::AddressSpaceType::AddressSpace36Bit) { if (process->memory.addressSpaceType == memory::AddressSpaceType::AddressSpace36Bit) {
process->memory.MapHeapMemory(span<u8>{base, patch.size + hookSize}); // --- 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 { } else {
process->memory.Reserve(span<u8>{base, patch.size + hookSize}); // --- process->memory.Reserve(span<u8>{base, patch.size + hookSize}); // ---
} }