diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index a0e13bad..7ad8ff70 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -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(base.data()), base.size()); + if (addressSpaceType != memory::AddressSpaceType::AddressSpace39Bit) + if (codeBase36Bit.valid() && !codeBase36Bit.empty()) + munmap(reinterpret_cast(codeBase36Bit.data()), codeBase36Bit.size()); } - std::map::iterator MemoryManager::upper_bound(u8 *address) { - std::map::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 *newDesc) { + void MemoryManager::MapInternal(const std::pair &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(newDesc->first - firstChunkBase->first); + firstChunk.size = static_cast(newDesc.first - firstChunkBase->first); chunks[firstChunkBase->first] = firstChunk; // We create the chunk's second half - lastChunk.size = static_cast((lastChunkBase->first + lastChunk.size) - (newDesc->first + newDesc->second.size)); - chunks[newDesc->first + newDesc->second.size] = lastChunk; + lastChunk.size = static_cast((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((newDesc->first + newDesc->second.size) - firstChunkBase->first); + firstChunk.size = static_cast((newDesc.first + newDesc.second.size) - firstChunkBase->first); chunks[firstChunkBase->first] = firstChunk; - } else if ((firstChunkBase->first + firstChunk.size) != newDesc->first) { - firstChunk.size = static_cast(newDesc->first - firstChunkBase->first); + } else if ((firstChunkBase->first + firstChunk.size) != newDesc.first) { + firstChunk.size = static_cast(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((lastChunk.size + oldBase) - (newDesc->first)); + lastChunk.size = static_cast((lastChunk.size + oldBase) - (newDesc.first)); - chunks[newDesc->first] = lastChunk; + chunks[newDesc.first] = lastChunk; } else { firstChunk.size = static_cast((lastChunk.size + oldBase) - firstChunkBase->first); chunks[firstChunkBase->first] = firstChunk; } - } else if ((newDesc->first + newDesc->second.size) != lastChunkBase->first) { - lastChunk.size = static_cast((lastChunk.size + lastChunkBase->first) - (newDesc->first + newDesc->second.size)); + } else if ((newDesc.first + newDesc.second.size) != lastChunkBase->first) { + lastChunk.size = static_cast((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 memory, auto editCallback) { - auto chunkBase{upper_bound(memory.data())}; + void MemoryManager::ForeachChunkinRange(span 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(resultChunk.size - (static_cast(memory.data() - chunkBase->first)), memory.size())}; + if (chunkBase->first < memory.data()) [[unlikely]] { + size_t chunkSize{std::min(chunkBase->second.size - (static_cast(memory.data() - chunkBase->first)), memory.size())}; - std::pair temp(memory.data(), resultChunk); - temp.second.size = copySize; + std::pair 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 temp(chunkBase->first, resultChunk); + if (sizeLeft < chunkBase->second.size) { + std::pair temp(*chunkBase); temp.second.size = sizeLeft; editCallback(temp); break; } else [[likely]] { - std::pair temp(chunkBase->first, resultChunk); + std::pair 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(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{reinterpret_cast(0), 1ULL << 39}; } - - chunks[addressSpace.data()] = ChunkDescriptor{ - .size = addressSpace.size(), - .state = memory::states::Unmapped, - }; - - code = codeBase36Bit; } + + // 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, + }}, {reinterpret_cast(UINT64_MAX), { + .state = memory::states::Reserved, + }}}; } void MemoryManager::InitializeRegions(span 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(0x8000000)) { - std::pair tmp(reinterpret_cast(0x8000000), ChunkDescriptor{ + MapInternal(std::pair(reinterpret_cast(0x8000000),{ .size = reinterpret_cast(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{reinterpret_cast(mirrorBase), totalSize}; } - void MemoryManager::SetLockOnChunks(span memory, bool value) { - std::unique_lock lock(mutex); + void MemoryManager::SetRegionBorrowed(span memory, bool value) { + std::unique_lock lock{mutex}; ForeachChunkinRange(memory, [&](std::pair &desc) __attribute__((always_inline)) { desc.second.attributes.isBorrowed = value; - MapInternal(&desc); + MapInternal(desc); }); } - void MemoryManager::SetCPUCachingOnChunks(span memory, bool value) { - std::unique_lock lock(mutex); + void MemoryManager::SetRegionCpuCaching(span memory, bool value) { + std::unique_lock lock{mutex}; ForeachChunkinRange(memory, [&](std::pair &desc) __attribute__((always_inline)) { desc.second.attributes.isUncached = value; - MapInternal(&desc); + MapInternal(desc); }); } - void MemoryManager::SetChunkPermission(span memory, memory::Permission permission) { - std::unique_lock lock(mutex); + void MemoryManager::SetRegionPermission(span memory, memory::Permission permission) { + std::unique_lock lock{mutex}; ForeachChunkinRange(memory, [&](std::pair &desc) __attribute__((always_inline)) { desc.second.permission = permission; - MapInternal(&desc); + MapInternal(desc); }); } std::optional> 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 memory, memory::Permission permission) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + memory.data(),{ .size = memory.size(), .permission = permission, - .state = memory::states::Code}); - - MapInternal(&temp); + .state = memory::states::Code + })); } __attribute__((always_inline)) void MemoryManager::MapMutableCodeMemory(span memory) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + 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 memory) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + 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 memory) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + 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 memory, memory::Permission permission) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + memory.data(),{ .size = memory.size(), .permission = permission, .state = memory::states::SharedMemory, - .isSrcMergeDisallowed = true}); - - MapInternal(&temp); + .isSrcMergeDisallowed = true + })); } __attribute__((always_inline)) void MemoryManager::MapTransferMemory(span memory, memory::Permission permission) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + 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 memory) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + 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 memory) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - std::pair temp( - memory.data(), - ChunkDescriptor{ + MapInternal(std::pair( + 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 memory) { - std::unique_lock lock(mutex); + std::unique_lock lock{mutex}; - ForeachChunkinRange(memory, [&](std::pair &desc) { + ForeachChunkinRange(memory, [&](const std::pair &desc) { if (desc.second.state != memory::states::Unmapped) - FreeMemory(span((u8 *)desc.first, desc.second.size)); + FreeMemory(span(desc.first, desc.second.size)); }); - std::pair temp( - memory.data(), - ChunkDescriptor{ - .size = memory.size(), - .permission = {false, false, false}, - .state = memory::states::Unmapped}); - MapInternal(&temp); + MapInternal(std::pair( + memory.data(),{ + .size = memory.size(), + .permission = {false, false, false}, + .state = memory::states::Unmapped + })); } __attribute__((always_inline)) void MemoryManager::FreeMemory(span memory) { @@ -535,25 +500,23 @@ namespace skyline::kernel { Logger::Error("Failed to free memory: {}", strerror(errno)); } - void MemoryManager::AddRef(const std::shared_ptr &ptr) { - memRefs.push_back(ptr); + void MemoryManager::AddRef(std::shared_ptr ptr) { + memRefs.push_back(std::move(ptr)); } - void MemoryManager::RemoveRef(const std::shared_ptr &ptr) { - std::vector>::iterator i{std::find(memRefs.begin(), memRefs.end(), ptr)}; + void MemoryManager::RemoveRef(std::shared_ptr 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(state.process->npdm.meta.systemResourceSize), util::AlignUp(chunks.size() * KMemoryBlockSize, constant::PageSize)); } diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index e2d1d51b..5bc93b52 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -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> memRefs; - // Workaround for broken std implementation - std::map::iterator upper_bound(u8 *address); - - void MapInternal(std::pair *newDesc); + void MapInternal(const std::pair &newDesc); void ForeachChunkinRange(span memory, auto editCallback); @@ -240,7 +242,7 @@ namespace skyline { span stack{}; span 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 CreateMirrors(const std::vector> ®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 memory, bool value); - - void SetCPUCachingOnChunks(span memory, bool value); + void SetRegionBorrowed(span 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 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 memory, memory::Permission permission); + void SetRegionPermission(span memory, memory::Permission permission); /** * @brief Gets the highest chunk's descriptor that contains this address */ std::optional> 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 memory, memory::Permission permission); void MapMutableCodeMemory(span memory); @@ -309,6 +311,9 @@ namespace skyline { void Reserve(span memory); + /** + * @note `UnmapMemory` also calls `FreeMemory` on the unmapped memory range + */ void UnmapMemory(span memory); /** @@ -318,11 +323,14 @@ namespace skyline { void FreeMemory(span 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 &ptr); + void AddRef(std::shared_ptr ptr); - void RemoveRef(const std::shared_ptr &ptr); + /** + * @brief Removes the reference added by `AddRef` + */ + void RemoveRef(std::shared_ptr 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 { + template + constexpr auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + template + 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' : '-'); + } +}; diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 84c10cb2..b4033c28 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -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{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(heapBaseAddr); @@ -67,7 +67,7 @@ namespace skyline::kernel::svc { memory::Permission newPermission(static_cast(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(address, size), newPermission); + state.process->memory.SetRegionPermission(span(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(state.ctx->gpr.w2)}; + memory::MemoryAttribute value{static_cast(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{address, size}, value.isUncached); + state.process->memory.SetRegionCpuCaching(span{address, size}, value.isUncached); Logger::Debug("Set CPU caching to {} at 0x{:X} - 0x{:X} (0x{:X} bytes)", static_cast(value.isUncached), address, address + size, size); state.ctx->gpr.w0 = Result{}; @@ -175,8 +175,8 @@ namespace skyline::kernel::svc { state.process->memory.MapStackMemory(span{destination, size}); std::memcpy(destination, source, size); - state.process->memory.SetChunkPermission(span{source, size}, {false, false, false}); - state.process->memory.SetLockOnChunks(span{source, size}, true); + state.process->memory.SetRegionPermission(span{source, size}, {false, false, false}); + state.process->memory.SetRegionBorrowed(span{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{source + (dstChunk.first - destination), dstChunk.second.size}, dstChunk.second.permission); - state.process->memory.SetLockOnChunks(span{source + (dstChunk.first - destination), dstChunk.second.size}, false); + state.process->memory.SetRegionPermission(span{source + (dstChunk.first - destination), dstChunk.second.size}, dstChunk.second.permission); + state.process->memory.SetRegionBorrowed(span{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(state.process->memory.addressSpace.end().base())}; @@ -254,7 +254,7 @@ namespace skyline::kernel::svc { *reinterpret_cast(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(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(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; } diff --git a/app/src/main/cpp/skyline/kernel/types/KMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KMemory.cpp index 90ac788c..7f77c4ff 100644 --- a/app/src/main/cpp/skyline/kernel/types/KMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KMemory.cpp @@ -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(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0))}; + u8 *hostPtr{static_cast(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); } } \ No newline at end of file diff --git a/app/src/main/cpp/skyline/kernel/types/KMemory.h b/app/src/main/cpp/skyline/kernel/types/KMemory.h index 48b3e429..88a6d9f0 100644 --- a/app/src/main/cpp/skyline/kernel/types/KMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KMemory.h @@ -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); diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index 31ed9acc..65d2c4fb 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -50,7 +50,7 @@ namespace skyline::kernel::type { void KProcess::InitializeHeapTls() { constexpr size_t DefaultHeapSize{0x200000}; memory.MapHeapMemory(span{state.process->memory.heap.data(), DefaultHeapSize}); - memory.setHeapSize = DefaultHeapSize; + memory.processHeapSize = DefaultHeapSize; tlsExceptionContext = AllocateTlsSlot(); } diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index 3091c358..31f616b3 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -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 map, memory::Permission permission) { u8 *result{KMemory::Map(map, permission)}; diff --git a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp index fecd138b..b5bb44cd 100644 --- a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp @@ -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 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; } } diff --git a/app/src/main/cpp/skyline/loader/loader.cpp b/app/src/main/cpp/skyline/loader/loader.cpp index 8db204c1..fe86cb96 100644 --- a/app/src/main/cpp/skyline/loader/loader.cpp +++ b/app/src/main/cpp/skyline/loader/loader.cpp @@ -91,7 +91,7 @@ namespace skyline::loader { if (process->memory.addressSpaceType == memory::AddressSpaceType::AddressSpace36Bit) { process->memory.MapHeapMemory(span{base, patch.size + hookSize}); // --- - process->memory.SetChunkPermission(span{base, patch.size + hookSize}, memory::Permission{false, false, false}); + process->memory.SetRegionPermission(span{base, patch.size + hookSize}, memory::Permission{false, false, false}); } else { process->memory.Reserve(span{base, patch.size + hookSize}); // --- }