kernel: implement remaining IPC syscalls
This commit is contained in:
		| @@ -10,9 +10,7 @@ | |||||||
|  |  | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
|  |  | ||||||
| static constexpr u32 MessageBufferSize = 0x100; | KClientSession::KClientSession(KernelCore& kernel) : KAutoObject{kernel} {} | ||||||
|  |  | ||||||
| KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} |  | ||||||
| KClientSession::~KClientSession() = default; | KClientSession::~KClientSession() = default; | ||||||
|  |  | ||||||
| void KClientSession::Destroy() { | void KClientSession::Destroy() { | ||||||
| @@ -22,18 +20,30 @@ void KClientSession::Destroy() { | |||||||
|  |  | ||||||
| void KClientSession::OnServerClosed() {} | void KClientSession::OnServerClosed() {} | ||||||
|  |  | ||||||
| Result KClientSession::SendSyncRequest() { | Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) { | ||||||
|     // Create a session request. |     // Create a session request. | ||||||
|     KSessionRequest* request = KSessionRequest::Create(m_kernel); |     KSessionRequest* request = KSessionRequest::Create(m_kernel); | ||||||
|     R_UNLESS(request != nullptr, ResultOutOfResource); |     R_UNLESS(request != nullptr, ResultOutOfResource); | ||||||
|     SCOPE_EXIT({ request->Close(); }); |     SCOPE_EXIT({ request->Close(); }); | ||||||
|  |  | ||||||
|     // Initialize the request. |     // Initialize the request. | ||||||
|     request->Initialize(nullptr, GetInteger(GetCurrentThread(m_kernel).GetTlsAddress()), |     request->Initialize(nullptr, address, size); | ||||||
|                         MessageBufferSize); |  | ||||||
|  |  | ||||||
|     // Send the request. |     // Send the request. | ||||||
|     R_RETURN(m_parent->GetServerSession().OnRequest(request)); |     R_RETURN(m_parent->OnRequest(request)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t size) { | ||||||
|  |     // Create a session request. | ||||||
|  |     KSessionRequest* request = KSessionRequest::Create(m_kernel); | ||||||
|  |     R_UNLESS(request != nullptr, ResultOutOfResource); | ||||||
|  |     SCOPE_EXIT({ request->Close(); }); | ||||||
|  |  | ||||||
|  |     // Initialize the request. | ||||||
|  |     request->Initialize(event, address, size); | ||||||
|  |  | ||||||
|  |     // Send the request. | ||||||
|  |     R_RETURN(m_parent->OnRequest(request)); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace Kernel | } // namespace Kernel | ||||||
|   | |||||||
| @@ -9,24 +9,12 @@ | |||||||
| #include "core/hle/kernel/slab_helpers.h" | #include "core/hle/kernel/slab_helpers.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
|  |  | ||||||
| union Result; |  | ||||||
|  |  | ||||||
| namespace Core::Memory { |  | ||||||
| class Memory; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| namespace Core::Timing { |  | ||||||
| class CoreTiming; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
|  |  | ||||||
| class KernelCore; | class KernelCore; | ||||||
| class KSession; | class KSession; | ||||||
| class KThread; |  | ||||||
|  |  | ||||||
| class KClientSession final | class KClientSession final : public KAutoObject { | ||||||
|     : public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> { |  | ||||||
|     KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); |     KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); | ||||||
|  |  | ||||||
| public: | public: | ||||||
| @@ -39,13 +27,13 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Destroy() override; |     void Destroy() override; | ||||||
|     static void PostDestroy(uintptr_t arg) {} |  | ||||||
|  |  | ||||||
|     KSession* GetParent() const { |     KSession* GetParent() const { | ||||||
|         return m_parent; |         return m_parent; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Result SendSyncRequest(); |     Result SendSyncRequest(uintptr_t address, size_t size); | ||||||
|  |     Result SendAsyncRequest(KEvent* event, uintptr_t address, size_t size); | ||||||
|  |  | ||||||
|     void OnServerClosed(); |     void OnServerClosed(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -453,6 +453,11 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext | |||||||
|     size_t client_buffer_size = request->GetSize(); |     size_t client_buffer_size = request->GetSize(); | ||||||
|     // bool recv_list_broken = false; |     // bool recv_list_broken = false; | ||||||
|  |  | ||||||
|  |     if (!client_message) { | ||||||
|  |         client_message = GetInteger(client_thread->GetTlsAddress()); | ||||||
|  |         client_buffer_size = MessageBufferSize; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Receive the message. |     // Receive the message. | ||||||
|     Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; |     Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; | ||||||
|     if (out_context != nullptr) { |     if (out_context != nullptr) { | ||||||
|   | |||||||
| @@ -46,6 +46,10 @@ public: | |||||||
|         return this->GetState() != State::Normal; |         return this->GetState() != State::Normal; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     Result OnRequest(KSessionRequest* request) { | ||||||
|  |         R_RETURN(m_server.OnRequest(request)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     KClientSession& GetClientSession() { |     KClientSession& GetClientSession() { | ||||||
|         return m_client; |         return m_client; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -7,71 +7,39 @@ | |||||||
| #include "core/hle/kernel/k_client_session.h" | #include "core/hle/kernel/k_client_session.h" | ||||||
| #include "core/hle/kernel/k_hardware_timer.h" | #include "core/hle/kernel/k_hardware_timer.h" | ||||||
| #include "core/hle/kernel/k_process.h" | #include "core/hle/kernel/k_process.h" | ||||||
|  | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||||||
| #include "core/hle/kernel/k_server_session.h" | #include "core/hle/kernel/k_server_session.h" | ||||||
|  | #include "core/hle/kernel/k_session.h" | ||||||
| #include "core/hle/kernel/svc.h" | #include "core/hle/kernel/svc.h" | ||||||
| #include "core/hle/kernel/svc_results.h" | #include "core/hle/kernel/svc_results.h" | ||||||
|  |  | ||||||
| namespace Kernel::Svc { | namespace Kernel::Svc { | ||||||
|  |  | ||||||
| /// Makes a blocking IPC call to a service. | namespace { | ||||||
| Result SendSyncRequest(Core::System& system, Handle handle) { |  | ||||||
|     // Get the client session from its handle. | Result SendSyncRequestImpl(KernelCore& kernel, uintptr_t message, size_t buffer_size, | ||||||
|  |                            Handle session_handle) { | ||||||
|  |     // Get the client session. | ||||||
|     KScopedAutoObject session = |     KScopedAutoObject session = | ||||||
|         GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KClientSession>(handle); |         GetCurrentProcess(kernel).GetHandleTable().GetObject<KClientSession>(session_handle); | ||||||
|     R_UNLESS(session.IsNotNull(), ResultInvalidHandle); |     R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||||||
|  |  | ||||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); |     // Get the parent, and persist a reference to it until we're done. | ||||||
|  |     KScopedAutoObject parent = session->GetParent(); | ||||||
|  |     ASSERT(parent.IsNotNull()); | ||||||
|  |  | ||||||
|     R_RETURN(session->SendSyncRequest()); |     // Send the request. | ||||||
|  |     R_RETURN(session->SendSyncRequest(message, buffer_size)); | ||||||
| } | } | ||||||
|  |  | ||||||
| Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer, | Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t message, | ||||||
|                                      uint64_t message_buffer_size, Handle session_handle) { |                            size_t buffer_size, KPhysicalAddress message_paddr, | ||||||
|     UNIMPLEMENTED(); |                            KSynchronizationObject** objs, int32_t num_objects, Handle reply_target, | ||||||
|     R_THROW(ResultNotImplemented); |                            int64_t timeout_ns) { | ||||||
| } |  | ||||||
|  |  | ||||||
| Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, |  | ||||||
|                                       uint64_t message_buffer, uint64_t message_buffer_size, |  | ||||||
|                                       Handle session_handle) { |  | ||||||
|     UNIMPLEMENTED(); |  | ||||||
|     R_THROW(ResultNotImplemented); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles, |  | ||||||
|                        Handle reply_target, s64 timeout_ns) { |  | ||||||
|     // Ensure number of handles is valid. |  | ||||||
|     R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); |  | ||||||
|  |  | ||||||
|     // Get the synchronization context. |  | ||||||
|     auto& kernel = system.Kernel(); |  | ||||||
|     auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); |  | ||||||
|     auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer(); |  | ||||||
|     auto handles = GetCurrentThread(kernel).GetHandleBuffer(); |  | ||||||
|  |  | ||||||
|     // Copy user handles. |  | ||||||
|     if (num_handles > 0) { |  | ||||||
|         // Get the handles. |  | ||||||
|         R_UNLESS(GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), |  | ||||||
|                                                     sizeof(Handle) * num_handles), |  | ||||||
|                  ResultInvalidPointer); |  | ||||||
|  |  | ||||||
|         // Convert the handles to objects. |  | ||||||
|         R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>( |  | ||||||
|                      objs.data(), handles.data(), num_handles), |  | ||||||
|                  ResultInvalidHandle); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Ensure handles are closed when we're done. |  | ||||||
|     SCOPE_EXIT({ |  | ||||||
|         for (auto i = 0; i < num_handles; ++i) { |  | ||||||
|             objs[i]->Close(); |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     // Reply to the target, if one is specified. |     // Reply to the target, if one is specified. | ||||||
|     if (reply_target != InvalidHandle) { |     if (reply_target != InvalidHandle) { | ||||||
|         KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target); |         KScopedAutoObject session = | ||||||
|  |             GetCurrentProcess(kernel).GetHandleTable().GetObject<KServerSession>(reply_target); | ||||||
|         R_UNLESS(session.IsNotNull(), ResultInvalidHandle); |         R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||||||
|  |  | ||||||
|         // If we fail to reply, we want to set the output index to -1. |         // If we fail to reply, we want to set the output index to -1. | ||||||
| @@ -81,57 +49,223 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad | |||||||
|  |  | ||||||
|         // Send the reply. |         // Send the reply. | ||||||
|         R_TRY(session->SendReply()); |         R_TRY(session->SendReply()); | ||||||
|  |         // R_TRY(session->SendReply(message, buffer_size, message_paddr)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Convert the timeout from nanoseconds to ticks. |     // Receive a message. | ||||||
|     // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... |     { | ||||||
|     s64 timeout; |         // Convert the timeout from nanoseconds to ticks. | ||||||
|     if (timeout_ns > 0) { |         // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... | ||||||
|         const s64 offset_tick(timeout_ns); |         s64 timeout; | ||||||
|         if (offset_tick > 0) { |         if (timeout_ns > 0) { | ||||||
|             timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2; |             const s64 offset_tick(timeout_ns); | ||||||
|             if (timeout <= 0) { |             if (offset_tick > 0) { | ||||||
|  |                 timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2; | ||||||
|  |                 if (timeout <= 0) { | ||||||
|  |                     timeout = std::numeric_limits<s64>::max(); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|                 timeout = std::numeric_limits<s64>::max(); |                 timeout = std::numeric_limits<s64>::max(); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             timeout = std::numeric_limits<s64>::max(); |             timeout = timeout_ns; | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         timeout = timeout_ns; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Wait for a message. |  | ||||||
|     while (true) { |  | ||||||
|         // Wait for an object. |  | ||||||
|         s32 index; |  | ||||||
|         Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), |  | ||||||
|                                                      num_handles, timeout); |  | ||||||
|         if (result == ResultTimedOut) { |  | ||||||
|             R_RETURN(result); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Receive the request. |         // Wait for a message. | ||||||
|         if (R_SUCCEEDED(result)) { |         while (true) { | ||||||
|             KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); |             // Wait for an object. | ||||||
|             if (session != nullptr) { |             s32 index; | ||||||
|                 result = session->ReceiveRequest(); |             Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs, | ||||||
|                 if (result == ResultNotFound) { |                                                          num_objects, timeout); | ||||||
|                     continue; |             if (ResultTimedOut == result) { | ||||||
|  |                 R_THROW(result); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Receive the request. | ||||||
|  |             if (R_SUCCEEDED(result)) { | ||||||
|  |                 KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); | ||||||
|  |                 if (session != nullptr) { | ||||||
|  |                     // result = session->ReceiveRequest(message, buffer_size, message_paddr); | ||||||
|  |                     result = session->ReceiveRequest(); | ||||||
|  |                     if (ResultNotFound == result) { | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |  | ||||||
|  |  | ||||||
|         *out_index = index; |             *out_index = index; | ||||||
|         R_RETURN(result); |             R_RETURN(result); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, | Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t message, | ||||||
|                                      uint64_t message_buffer, uint64_t message_buffer_size, |                            size_t buffer_size, KPhysicalAddress message_paddr, | ||||||
|                                      uint64_t handles, int32_t num_handles, Handle reply_target, |                            KProcessAddress user_handles, int32_t num_handles, Handle reply_target, | ||||||
|                                      int64_t timeout_ns) { |                            int64_t timeout_ns) { | ||||||
|     UNIMPLEMENTED(); |     // Ensure number of handles is valid. | ||||||
|     R_THROW(ResultNotImplemented); |     R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); | ||||||
|  |  | ||||||
|  |     // Get the synchronization context. | ||||||
|  |     auto& process = GetCurrentProcess(kernel); | ||||||
|  |     auto& thread = GetCurrentThread(kernel); | ||||||
|  |     auto& handle_table = process.GetHandleTable(); | ||||||
|  |     KSynchronizationObject** objs = thread.GetSynchronizationObjectBuffer().data(); | ||||||
|  |     Handle* handles = thread.GetHandleBuffer().data(); | ||||||
|  |  | ||||||
|  |     // Copy user handles. | ||||||
|  |     if (num_handles > 0) { | ||||||
|  |         // Ensure that we can try to get the handles. | ||||||
|  |         R_UNLESS(process.GetPageTable().Contains(user_handles, num_handles * sizeof(Handle)), | ||||||
|  |                  ResultInvalidPointer); | ||||||
|  |  | ||||||
|  |         // Get the handles | ||||||
|  |         R_UNLESS( | ||||||
|  |             GetCurrentMemory(kernel).ReadBlock(user_handles, handles, sizeof(Handle) * num_handles), | ||||||
|  |             ResultInvalidPointer); | ||||||
|  |  | ||||||
|  |         // Convert the handles to objects. | ||||||
|  |         R_UNLESS( | ||||||
|  |             handle_table.GetMultipleObjects<KSynchronizationObject>(objs, handles, num_handles), | ||||||
|  |             ResultInvalidHandle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Ensure handles are closed when we're done. | ||||||
|  |     SCOPE_EXIT({ | ||||||
|  |         for (auto i = 0; i < num_handles; ++i) { | ||||||
|  |             objs[i]->Close(); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs, | ||||||
|  |                                  num_handles, reply_target, timeout_ns)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace | ||||||
|  |  | ||||||
|  | /// Makes a blocking IPC call to a service. | ||||||
|  | Result SendSyncRequest(Core::System& system, Handle session_handle) { | ||||||
|  |     R_RETURN(SendSyncRequestImpl(system.Kernel(), 0, 0, session_handle)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message, uint64_t buffer_size, | ||||||
|  |                                      Handle session_handle) { | ||||||
|  |     auto& kernel = system.Kernel(); | ||||||
|  |  | ||||||
|  |     // Validate that the message buffer is page aligned and does not overflow. | ||||||
|  |     R_UNLESS(Common::IsAligned(message, PageSize), ResultInvalidAddress); | ||||||
|  |     R_UNLESS(buffer_size > 0, ResultInvalidSize); | ||||||
|  |     R_UNLESS(Common::IsAligned(buffer_size, PageSize), ResultInvalidSize); | ||||||
|  |     R_UNLESS(message < message + buffer_size, ResultInvalidCurrentMemory); | ||||||
|  |  | ||||||
|  |     // Get the process page table. | ||||||
|  |     auto& page_table = GetCurrentProcess(kernel).GetPageTable(); | ||||||
|  |  | ||||||
|  |     // Lock the message buffer. | ||||||
|  |     R_TRY(page_table.LockForIpcUserBuffer(nullptr, message, buffer_size)); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         // If we fail to send the message, unlock the message buffer. | ||||||
|  |         ON_RESULT_FAILURE { | ||||||
|  |             page_table.UnlockForIpcUserBuffer(message, buffer_size); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Send the request. | ||||||
|  |         ASSERT(message != 0); | ||||||
|  |         R_TRY(SendSyncRequestImpl(kernel, message, buffer_size, session_handle)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // We successfully processed, so try to unlock the message buffer. | ||||||
|  |     R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, | ||||||
|  |                                       uint64_t message, uint64_t buffer_size, | ||||||
|  |                                       Handle session_handle) { | ||||||
|  |     // Get the process and handle table. | ||||||
|  |     auto& process = GetCurrentProcess(system.Kernel()); | ||||||
|  |     auto& handle_table = process.GetHandleTable(); | ||||||
|  |  | ||||||
|  |     // Reserve a new event from the process resource limit. | ||||||
|  |     KScopedResourceReservation event_reservation(std::addressof(process), | ||||||
|  |                                                  Svc::LimitableResource::EventCountMax); | ||||||
|  |     R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); | ||||||
|  |  | ||||||
|  |     // Get the client session. | ||||||
|  |     KScopedAutoObject session = process.GetHandleTable().GetObject<KClientSession>(session_handle); | ||||||
|  |     R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||||||
|  |  | ||||||
|  |     // Get the parent, and persist a reference to it until we're done. | ||||||
|  |     KScopedAutoObject parent = session->GetParent(); | ||||||
|  |     ASSERT(parent.IsNotNull()); | ||||||
|  |  | ||||||
|  |     // Create a new event. | ||||||
|  |     KEvent* event = KEvent::Create(system.Kernel()); | ||||||
|  |     R_UNLESS(event != nullptr, ResultOutOfResource); | ||||||
|  |  | ||||||
|  |     // Initialize the event. | ||||||
|  |     event->Initialize(std::addressof(process)); | ||||||
|  |  | ||||||
|  |     // Commit our reservation. | ||||||
|  |     event_reservation.Commit(); | ||||||
|  |  | ||||||
|  |     // At end of scope, kill the standing references to the sub events. | ||||||
|  |     SCOPE_EXIT({ | ||||||
|  |         event->GetReadableEvent().Close(); | ||||||
|  |         event->Close(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // Register the event. | ||||||
|  |     KEvent::Register(system.Kernel(), event); | ||||||
|  |  | ||||||
|  |     // Add the readable event to the handle table. | ||||||
|  |     R_TRY(handle_table.Add(out_event_handle, std::addressof(event->GetReadableEvent()))); | ||||||
|  |  | ||||||
|  |     // Ensure that if we fail to send the request, we close the readable handle. | ||||||
|  |     ON_RESULT_FAILURE { | ||||||
|  |         handle_table.Remove(*out_event_handle); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // Send the async request. | ||||||
|  |     R_RETURN(session->SendAsyncRequest(event, message, buffer_size)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles, s32 num_handles, | ||||||
|  |                        Handle reply_target, s64 timeout_ns) { | ||||||
|  |     R_RETURN(ReplyAndReceiveImpl(system.Kernel(), out_index, 0, 0, 0, handles, num_handles, | ||||||
|  |                                  reply_target, timeout_ns)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, uint64_t message, | ||||||
|  |                                      uint64_t buffer_size, uint64_t handles, int32_t num_handles, | ||||||
|  |                                      Handle reply_target, int64_t timeout_ns) { | ||||||
|  |     // Validate that the message buffer is page aligned and does not overflow. | ||||||
|  |     R_UNLESS(Common::IsAligned(message, PageSize), ResultInvalidAddress); | ||||||
|  |     R_UNLESS(buffer_size > 0, ResultInvalidSize); | ||||||
|  |     R_UNLESS(Common::IsAligned(buffer_size, PageSize), ResultInvalidSize); | ||||||
|  |     R_UNLESS(message < message + buffer_size, ResultInvalidCurrentMemory); | ||||||
|  |  | ||||||
|  |     // Get the process page table. | ||||||
|  |     auto& page_table = GetCurrentProcess(system.Kernel()).GetPageTable(); | ||||||
|  |  | ||||||
|  |     // Lock the message buffer, getting its physical address. | ||||||
|  |     KPhysicalAddress message_paddr; | ||||||
|  |     R_TRY(page_table.LockForIpcUserBuffer(std::addressof(message_paddr), message, buffer_size)); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         // If we fail to send the message, unlock the message buffer. | ||||||
|  |         ON_RESULT_FAILURE { | ||||||
|  |             page_table.UnlockForIpcUserBuffer(message, buffer_size); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Reply/Receive the request. | ||||||
|  |         ASSERT(message != 0); | ||||||
|  |         R_TRY(ReplyAndReceiveImpl(system.Kernel(), out_index, message, buffer_size, message_paddr, | ||||||
|  |                                   handles, num_handles, reply_target, timeout_ns)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // We successfully processed, so try to unlock the message buffer. | ||||||
|  |     R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size)); | ||||||
| } | } | ||||||
|  |  | ||||||
| Result SendSyncRequest64(Core::System& system, Handle session_handle) { | Result SendSyncRequest64(Core::System& system, Handle session_handle) { | ||||||
|   | |||||||
| @@ -192,8 +192,6 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques | |||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); |  | ||||||
|  |  | ||||||
|     *out_client_session = session; |     *out_client_session = session; | ||||||
|     return ResultSuccess; |     return ResultSuccess; | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user