diff --git a/app/src/main/cpp/skyline/input.h b/app/src/main/cpp/skyline/input.h index 382768c9..d9e3a78b 100644 --- a/app/src/main/cpp/skyline/input.h +++ b/app/src/main/cpp/skyline/input.h @@ -24,6 +24,6 @@ namespace skyline::input { NpadManager npad; TouchManager touch; - Input(const DeviceState &state) : state(state), kHid(std::make_shared(state, sizeof(HidSharedMemory))), hid(reinterpret_cast(kHid->kernel.ptr)), npad(state, hid), touch(state, hid) {} + Input(const DeviceState &state) : state(state), kHid(std::make_shared(state, sizeof(HidSharedMemory))), hid(reinterpret_cast(kHid->host.ptr)), npad(state, hid), touch(state, hid) {} }; } diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index f0f1c597..452e89f6 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -62,7 +62,7 @@ namespace skyline::kernel { throw exception("Cannot find a suitable carveout for the guest address space"); auto result{mmap(reinterpret_cast(base.address), base.size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)}; - if (result == MAP_FAILED) [[unlikely]] + if (result == MAP_FAILED) throw exception("Failed to mmap guest address space: {}", strerror(errno)); chunks = { diff --git a/app/src/main/cpp/skyline/kernel/scheduler.cpp b/app/src/main/cpp/skyline/kernel/scheduler.cpp index 8416fc14..255a838c 100644 --- a/app/src/main/cpp/skyline/kernel/scheduler.cpp +++ b/app/src/main/cpp/skyline/kernel/scheduler.cpp @@ -216,7 +216,7 @@ namespace skyline::kernel { auto &front{core.queue.front()}; if (front != thread) front->scheduleCondition.notify_one(); // If we aren't at the front of the queue, only then should we wake the thread at the front up - } else if (!thread->forceYield) [[unlikely]] { + } else if (!thread->forceYield) { throw exception("T{} called Rotate while not being in C{}'s queue", thread->id, thread->coreId); } diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index f74acda8..58ff2b20 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -508,6 +508,35 @@ namespace skyline::kernel::svc { } } + void UnmapSharedMemory(const DeviceState &state) { + try { + auto object{state.process->GetHandle(state.ctx->gpr.w0)}; + auto pointer{reinterpret_cast(state.ctx->gpr.x1)}; + + if (!util::PageAligned(pointer)) { + state.ctx->gpr.w0 = result::InvalidAddress; + state.logger->Warn("'pointer' not page aligned: 0x{:X}", pointer); + return; + } + + size_t size{state.ctx->gpr.x2}; + if (!util::PageAligned(size)) { + state.ctx->gpr.w0 = result::InvalidSize; + state.logger->Warn("'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); + return; + } + + state.logger->Debug("Unmapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes)", pointer, pointer + size, size); + + object->Unmap(pointer, size); + + state.ctx->gpr.w0 = Result{}; + } catch (const std::out_of_range &) { + state.logger->Warn("'handle' invalid: 0x{:X}", static_cast(state.ctx->gpr.w0)); + state.ctx->gpr.w0 = result::InvalidHandle; + } + } + void CreateTransferMemory(const DeviceState &state) { auto pointer{reinterpret_cast(state.ctx->gpr.x1)}; if (!util::PageAligned(pointer)) { diff --git a/app/src/main/cpp/skyline/kernel/svc.h b/app/src/main/cpp/skyline/kernel/svc.h index 99874e35..001dbf26 100644 --- a/app/src/main/cpp/skyline/kernel/svc.h +++ b/app/src/main/cpp/skyline/kernel/svc.h @@ -103,11 +103,17 @@ namespace skyline::kernel::svc { void ClearEvent(const DeviceState &state); /** - * @brief Maps the block supplied by the handle + * @brief Maps shared memory into a memory region * @url https://switchbrew.org/wiki/SVC#MapSharedMemory */ void MapSharedMemory(const DeviceState &state); + /** + * @brief Unmaps shared memory which has been mapped + * @url https://switchbrew.org/wiki/SVC#UnmapSharedMemory + */ + void UnmapSharedMemory(const DeviceState &state); + /** * @brief Returns a handle to a KSharedMemory object * @url https://switchbrew.org/wiki/SVC#CreateTransferMemory @@ -269,7 +275,7 @@ namespace skyline::kernel::svc { SVC_NONE, // 0x11 SVC_ENTRY(ClearEvent), // 0x12 SVC_ENTRY(MapSharedMemory), // 0x13 - SVC_NONE, // 0x14 + SVC_ENTRY(UnmapSharedMemory), // 0x14 SVC_ENTRY(CreateTransferMemory), // 0x15 SVC_ENTRY(CloseHandle), // 0x16 SVC_ENTRY(ResetSignal), // 0x17 diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index f254016f..98543615 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -13,12 +13,11 @@ namespace skyline::kernel::type { if (fd < 0) throw exception("An error occurred while creating shared memory: {}", fd); - kernel.ptr = reinterpret_cast(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0)); - if (kernel.ptr == MAP_FAILED) - [[unlikely]] - throw exception("An occurred while mapping shared memory: {}", strerror(errno)); + host.ptr = reinterpret_cast(mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0)); + if (host.ptr == MAP_FAILED) + throw exception("An occurred while mapping shared memory: {}", strerror(errno)); - kernel.size = size; + host.size = size; } u8 *KSharedMemory::Map(u8 *ptr, u64 size, memory::Permission permission) { @@ -26,11 +25,12 @@ namespace skyline::kernel::type { throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size); if (!util::PageAligned(ptr) || !util::PageAligned(size)) throw exception("KSharedMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size); + if (guest.Valid()) + throw exception("Mapping KSharedMemory multiple times on guest is not supported: Requested Mapping: 0x{:X} - 0x{:X} (0x{:X}), Current Mapping: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size, guest.ptr, guest.ptr + guest.size, guest.size); guest.ptr = reinterpret_cast(mmap(ptr, size, permission.Get(), MAP_SHARED | (ptr ? MAP_FIXED : 0), fd, 0)); if (guest.ptr == 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.size = size; state.process->memory.InsertChunk(ChunkDescriptor{ @@ -43,6 +43,25 @@ namespace skyline::kernel::type { return guest.ptr; } + void KSharedMemory::Unmap(u8 *ptr, u64 size) { + if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size)) + throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size); + if (!util::PageAligned(ptr) || !util::PageAligned(size)) + throw exception("KSharedMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size); + if (guest.ptr != ptr && guest.size != size) + throw exception("Unmapping KSharedMemory partially is not supported: Requested Unmap: 0x{:X} - 0x{:X} (0x{:X}), Current Mapping: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size, guest.ptr, guest.ptr + guest.size, guest.size); + + if (mmap(ptr, size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, 0, 0) == MAP_FAILED) + throw exception("An error occurred while unmapping shared memory in guest: {}", strerror(errno)); + + guest = {}; + state.process->memory.InsertChunk(ChunkDescriptor{ + .ptr = ptr, + .size = size, + .state = memory::states::Unmapped, + }); + } + void KSharedMemory::UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) { if (ptr && !util::PageAligned(ptr)) throw exception("KSharedMemory permission updated with a non-page-aligned address: 0x{:X}", ptr); @@ -50,8 +69,7 @@ namespace skyline::kernel::type { if (guest.Valid()) { mprotect(ptr, size, permission.Get()); if (guest.ptr == MAP_FAILED) - [[unlikely]] - throw exception("An error occurred while updating shared memory's permissions in guest: {}", strerror(errno)); + throw exception("An error occurred while updating shared memory's permissions in guest: {}", strerror(errno)); state.process->memory.InsertChunk(ChunkDescriptor{ .ptr = ptr, @@ -63,8 +81,8 @@ namespace skyline::kernel::type { } KSharedMemory::~KSharedMemory() { - if (kernel.Valid()) - munmap(kernel.ptr, kernel.size); + if (host.Valid()) + munmap(host.ptr, host.size); if (state.process && guest.Valid()) { mmap(guest.ptr, guest.size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // As this is the destructor, we cannot throw on this failing diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h index 24bdac5f..ec6484ec 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h @@ -22,7 +22,7 @@ namespace skyline::kernel::type { constexpr bool Valid() { return ptr && size; } - } kernel, guest{}; + } host, guest{}; //!< We keep two mirrors of the underlying shared memory for guest access and host access, the host mirror is persistently mapped and should be used by anything accessing the memory on the host KSharedMemory(const DeviceState &state, size_t size, memory::MemoryState memState = memory::states::SharedMemory, KType type = KType::KSharedMemory); @@ -31,6 +31,11 @@ namespace skyline::kernel::type { */ u8 *Map(u8 *ptr, u64 size, memory::Permission permission); + /** + * @note 'ptr' needs to be in guest-reserved address space + */ + void Unmap(u8 *ptr, u64 size); + span Get() override { return span(guest.ptr, guest.size); } diff --git a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h index c5b65b0c..1e3047f6 100644 --- a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h @@ -15,7 +15,7 @@ namespace skyline::kernel::type { * @note 'ptr' needs to be in guest-reserved address space */ KTransferMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory) : KSharedMemory(state, size, memState, KType::KTransferMemory) { - std::memcpy(kernel.ptr, ptr, size); + std::memcpy(host.ptr, ptr, size); Map(ptr, size, permission); } }; diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index c7d74724..a0d9ed85 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -23,7 +23,7 @@ namespace skyline::nce { if (svc) [[likely]] { TRACE_EVENT("kernel", perfetto::StaticString{svc.name}); (svc.function)(state); - } else [[unlikely]] { + } else { throw exception("Unimplemented SVC 0x{:X}", svcId); } diff --git a/app/src/main/cpp/skyline/services/pl/IPlatformServiceManager.cpp b/app/src/main/cpp/skyline/services/pl/IPlatformServiceManager.cpp index 5568baba..3b39a84c 100644 --- a/app/src/main/cpp/skyline/services/pl/IPlatformServiceManager.cpp +++ b/app/src/main/cpp/skyline/services/pl/IPlatformServiceManager.cpp @@ -33,11 +33,11 @@ namespace skyline::service::pl { constexpr u32 SharedFontMagic{0x36F81A1E}; //!< The encrypted magic for a single font in the shared font data constexpr u32 SharedFontKey{SharedFontMagic ^ SharedFontResult}; //!< The XOR key for encrypting the font size - auto ptr{reinterpret_cast(fontSharedMem->kernel.ptr)}; + auto ptr{reinterpret_cast(fontSharedMem->host.ptr)}; for (auto &font : fontTable) { *ptr++ = SharedFontResult; *ptr++ = font.length ^ SharedFontKey; - font.offset = reinterpret_cast(ptr) - reinterpret_cast(fontSharedMem->kernel.ptr); + font.offset = reinterpret_cast(ptr) - reinterpret_cast(fontSharedMem->host.ptr); std::memcpy(ptr, font.data, font.length); ptr = reinterpret_cast(reinterpret_cast(ptr) + font.length); diff --git a/app/src/main/cpp/skyline/services/timesrv/time_shared_memory.cpp b/app/src/main/cpp/skyline/services/timesrv/time_shared_memory.cpp index d567573a..7d4424d7 100644 --- a/app/src/main/cpp/skyline/services/timesrv/time_shared_memory.cpp +++ b/app/src/main/cpp/skyline/services/timesrv/time_shared_memory.cpp @@ -57,7 +57,7 @@ namespace skyline::service::timesrv::core { return out; } - TimeSharedMemory::TimeSharedMemory(const DeviceState &state) : kTimeSharedMemory(std::make_shared(state, TimeSharedMemorySize)), timeSharedMemory(reinterpret_cast(kTimeSharedMemory->kernel.ptr)) {} + TimeSharedMemory::TimeSharedMemory(const DeviceState &state) : kTimeSharedMemory(std::make_shared(state, TimeSharedMemorySize)), timeSharedMemory(reinterpret_cast(kTimeSharedMemory->host.ptr)) {} void TimeSharedMemory::SetupStandardSteadyClock(UUID rtcId, TimeSpanType baseTimePoint) { SteadyClockTimePoint context{ @@ -143,4 +143,4 @@ namespace skyline::service::timesrv::core { SignalOperationEvent(); return {}; } -} \ No newline at end of file +}