From f4fd4cbbb230dc8a9449cdf0803108e1b95de320 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 9 Jul 2020 20:11:41 -0700 Subject: [PATCH] kern: skeleton SvcReplyAndReceive --- .../include/mesosphere/kern_k_process.hpp | 1 + .../mesosphere/kern_k_server_session.hpp | 7 +- .../libmesosphere/source/kern_k_process.cpp | 4 + .../source/kern_k_server_session.cpp | 28 ++++++ .../libmesosphere/source/svc/kern_svc_ipc.cpp | 87 ++++++++++++++++++- .../source/svc/kern_svc_process.cpp | 9 +- 6 files changed, 131 insertions(+), 5 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 9eb2e52f1..02100f8ef 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -123,6 +123,7 @@ namespace ams::kern { virtual ~KProcess() { /* ... */ } Result Initialize(const ams::svc::CreateProcessParameter ¶ms, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool); + void Exit(); constexpr const char *GetName() const { return this->name; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp index 5f8ad5881..390fa16f3 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_server_session.hpp @@ -42,12 +42,17 @@ namespace ams::kern { constexpr const KSession *GetParent() const { return this->parent; } - virtual bool IsSignaled() const override { MESOSPHERE_UNIMPLEMENTED(); } + virtual bool IsSignaled() const override; /* TODO: More of KServerSession. */ Result OnRequest(KSessionRequest *request); + Result ReceiveRequest(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr); + Result SendReply(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr); + void OnClientClosed(); + private: + bool IsSignaledImpl() const; }; } diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index e178730d5..842fe1a2e 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -157,6 +157,10 @@ namespace ams::kern { MESOSPHERE_UNIMPLEMENTED(); } + void KProcess::Exit() { + MESOSPHERE_UNIMPLEMENTED(); + } + Result KProcess::CreateThreadLocalRegion(KProcessAddress *out) { KThreadLocalPage *tlp = nullptr; KProcessAddress tlr = Null; diff --git a/libraries/libmesosphere/source/kern_k_server_session.cpp b/libraries/libmesosphere/source/kern_k_server_session.cpp index cda3fb1d8..49f095f9f 100644 --- a/libraries/libmesosphere/source/kern_k_server_session.cpp +++ b/libraries/libmesosphere/source/kern_k_server_session.cpp @@ -48,6 +48,34 @@ namespace ams::kern { MESOSPHERE_UNIMPLEMENTED(); } + Result KServerSession::ReceiveRequest(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr) { + MESOSPHERE_UNIMPLEMENTED(); + } + + Result KServerSession::SendReply(uintptr_t message, uintptr_t buffer_size, KPhysicalAddress message_paddr) { + MESOSPHERE_UNIMPLEMENTED(); + } + + bool KServerSession::IsSignaledImpl() const { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); + + /* If the client is closed, we're always signaled. */ + if (this->parent->IsClientClosed()) { + return true; + } + + /* Otherwise, we're signaled if we have a request and aren't handling one. */ + return !this->request_list.empty() && this->current_request == nullptr; + } + + bool KServerSession::IsSignaled() const { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); + + return this->IsSignaledImpl(); + } + void KServerSession::OnClientClosed() { MESOSPHERE_ASSERT_THIS(); diff --git a/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp b/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp index 0d51e6a55..f6d0c9c51 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_ipc.cpp @@ -21,7 +21,90 @@ namespace ams::kern::svc { namespace { + ALWAYS_INLINE Result ReplyAndReceiveImpl(int32_t *out_index, uintptr_t message, size_t buffer_size, KPhysicalAddress message_paddr, KSynchronizationObject **objs, int32_t num_objects, ams::svc::Handle reply_target, int64_t timeout_ns) { + /* Reply to the target, if one is specified. */ + if (reply_target != ams::svc::InvalidHandle) { + /* TODO */ + MESOSPHERE_UNIMPLEMENTED(); + } + /* Receive a message. */ + { + /* Convert the timeout from nanoseconds to ticks. */ + /* NOTE: Nintendo does not use this conversion logic in WaitSynchronization... */ + s64 timeout; + if (timeout_ns > 0) { + const ams::svc::Tick offset_tick(TimeSpan::FromNanoSeconds(timeout_ns)); + if (AMS_LIKELY(offset_tick > 0)) { + timeout = KHardwareTimer::GetTick() + offset_tick + 2; + if (AMS_UNLIKELY(timeout <= 0)) { + timeout = std::numeric_limits::max(); + } + } else { + timeout = std::numeric_limits::max(); + } + } else { + timeout = timeout_ns; + } + + /* Wait for a message. */ + while (true) { + s32 index; + Result result = Kernel::GetSynchronization().Wait(std::addressof(index), objs, num_objects, timeout); + if (svc::ResultTimedOut::Includes(result)) { + return result; + } + + if (R_SUCCEEDED(result)) { + KServerSession *session = objs[index]->DynamicCast(); + if (session != nullptr) { + result = session->ReceiveRequest(message, buffer_size, message_paddr); + if (svc::ResultNotFound::Includes(result)) { + continue; + } + } + } + + *out_index = index; + return result; + } + } + } + + ALWAYS_INLINE Result ReplyAndReceiveImpl(int32_t *out_index, uintptr_t message, size_t buffer_size, KPhysicalAddress message_paddr, KUserPointer user_handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { + /* Ensure number of handles is valid. */ + R_UNLESS(0 <= num_handles && num_handles <= ams::svc::ArgumentHandleCountMax, svc::ResultOutOfRange()); + + /* Get the synchronization context. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + KSynchronizationObject **objs = GetCurrentThread().GetSynchronizationObjectBuffer(); + ams::svc::Handle *handles = GetCurrentThread().GetHandleBuffer(); + + /* Copy user handles. */ + if (num_handles > 0) { + /* Ensure that we can try to get the handles. */ + R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(user_handles.GetUnsafePointer()), num_handles * sizeof(ams::svc::Handle)), svc::ResultInvalidPointer()); + + /* Get the handles. */ + R_TRY(user_handles.CopyArrayTo(handles, num_handles)); + + /* Convert the handles to objects. */ + R_UNLESS(handle_table.GetMultipleObjects(objs, handles, num_handles), svc::ResultInvalidHandle()); + } + + /* Ensure handles are closed when we're done. */ + ON_SCOPE_EXIT { + for (auto i = 0; i < num_handles; ++i) { + objs[i]->Close(); + } + }; + + return ReplyAndReceiveImpl(out_index, message, buffer_size, message_paddr, objs, num_handles, reply_target, timeout_ns); + } + + ALWAYS_INLINE Result ReplyAndReceive(int32_t *out_index, KUserPointer handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { + return ReplyAndReceiveImpl(out_index, 0, 0, Null, handles, num_handles, reply_target, timeout_ns); + } } @@ -40,7 +123,7 @@ namespace ams::kern::svc { } Result ReplyAndReceive64(int32_t *out_index, KUserPointer handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { - MESOSPHERE_PANIC("Stubbed SvcReplyAndReceive64 was called."); + return ReplyAndReceive(out_index, handles, num_handles, reply_target, timeout_ns); } Result ReplyAndReceiveWithUserBuffer64(int32_t *out_index, ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, KUserPointer handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { @@ -62,7 +145,7 @@ namespace ams::kern::svc { } Result ReplyAndReceive64From32(int32_t *out_index, KUserPointer handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { - MESOSPHERE_PANIC("Stubbed SvcReplyAndReceive64From32 was called."); + return ReplyAndReceive(out_index, handles, num_handles, reply_target, timeout_ns); } Result ReplyAndReceiveWithUserBuffer64From32(int32_t *out_index, ams::svc::Address message_buffer, ams::svc::Size message_buffer_size, KUserPointer handles, int32_t num_handles, ams::svc::Handle reply_target, int64_t timeout_ns) { diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 4bf47cdda..df3f3d7f0 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -21,6 +21,11 @@ namespace ams::kern::svc { namespace { + void ExitProcess() { + GetCurrentProcess().Exit(); + MESOSPHERE_PANIC("Process survived call to exit"); + } + Result GetProcessId(u64 *out_process_id, ams::svc::Handle handle) { /* Get the object from the handle table. */ KScopedAutoObject obj = GetCurrentProcess().GetHandleTable().GetObject(handle); @@ -54,7 +59,7 @@ namespace ams::kern::svc { /* ============================= 64 ABI ============================= */ void ExitProcess64() { - MESOSPHERE_PANIC("Stubbed SvcExitProcess64 was called."); + return ExitProcess(); } Result GetProcessId64(uint64_t *out_process_id, ams::svc::Handle process_handle) { @@ -84,7 +89,7 @@ namespace ams::kern::svc { /* ============================= 64From32 ABI ============================= */ void ExitProcess64From32() { - MESOSPHERE_PANIC("Stubbed SvcExitProcess64From32 was called."); + return ExitProcess(); } Result GetProcessId64From32(uint64_t *out_process_id, ams::svc::Handle process_handle) {