diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 34b44fce14..079a39a7df 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -18,6 +18,7 @@ #include "core/hle/kernel/errors.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/ipc.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" @@ -453,6 +454,33 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand } } +static ResultCode ReceiveIPCRequest(Kernel::SharedPtr server_session, + Kernel::SharedPtr thread) { + if (server_session->parent->client == nullptr) { + return Kernel::ERR_SESSION_CLOSED_BY_REMOTE; + } + + VAddr target_address = thread->GetCommandBufferAddress(); + VAddr source_address = server_session->currently_handling->GetCommandBufferAddress(); + + ResultCode translation_result = Kernel::TranslateCommandBuffer( + server_session->currently_handling, thread, source_address, target_address); + + // If a translation error occurred, immediately resume the client thread. + if (translation_result.IsError()) { + // Set the output of SendSyncRequest in the client thread to the translation output. + server_session->currently_handling->SetWaitSynchronizationResult(translation_result); + + server_session->currently_handling->ResumeFromWait(); + server_session->currently_handling = nullptr; + + // TODO(Subv): This path should try to wait again on the same objects. + ASSERT_MSG(false, "ReplyAndReceive translation error behavior unimplemented"); + } + + return translation_result; +} + /// In a single operation, sends a IPC reply and waits for a new request. static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_count, Kernel::Handle reply_target) { @@ -495,7 +523,15 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ return Kernel::ERR_SESSION_CLOSED_BY_REMOTE; } - // TODO(Subv): Perform IPC translation from the current thread to request_thread. + VAddr source_address = Kernel::GetCurrentThread()->GetCommandBufferAddress(); + VAddr target_address = request_thread->GetCommandBufferAddress(); + + ResultCode translation_result = Kernel::TranslateCommandBuffer( + Kernel::GetCurrentThread(), request_thread, source_address, target_address); + + // Note: The real kernel seems to always panic if the Server->Client buffer translation + // fails for whatever reason. + ASSERT(translation_result.IsSuccess()); // Note: The scheduler is not invoked here. request_thread->ResumeFromWait(); @@ -524,14 +560,11 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ object->Acquire(thread); *index = static_cast(std::distance(objects.begin(), itr)); - if (object->GetHandleType() == Kernel::HandleType::ServerSession) { - auto server_session = static_cast(object); - if (server_session->parent->client == nullptr) - return Kernel::ERR_SESSION_CLOSED_BY_REMOTE; + if (object->GetHandleType() != Kernel::HandleType::ServerSession) + return RESULT_SUCCESS; - // TODO(Subv): Perform IPC translation from the ServerSession to the current thread. - } - return RESULT_SUCCESS; + auto server_session = static_cast(object); + return ReceiveIPCRequest(server_session, Kernel::GetCurrentThread()); } // No objects were ready to be acquired, prepare to suspend the thread. @@ -554,10 +587,15 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY); ASSERT(reason == ThreadWakeupReason::Signal); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get())); + ResultCode result = RESULT_SUCCESS; - // TODO(Subv): Perform IPC translation upon wakeup. + if (object->GetHandleType() == Kernel::HandleType::ServerSession) { + auto server_session = Kernel::DynamicObjectCast(object); + result = ReceiveIPCRequest(server_session, thread); + } + + thread->SetWaitSynchronizationResult(result); + thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get())); }; Core::System::GetInstance().PrepareReschedule();