diff options
author | Sebastian Valle <subv2112@gmail.com> | 2017-06-30 00:05:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-30 00:05:22 +0200 |
commit | 56d718b2a1d6385c88c2044f780280a5dfbc6072 (patch) | |
tree | a74b2c67bde47be93f2b2c3d55292bfbb421985a /src/core/hle/svc.cpp | |
parent | Merge pull request #2809 from wwylele/texture-copy-fix (diff) | |
parent | Kernel/SVC: Pass the current thread as a parameter to ClientSession::SendSyncRequest. (diff) | |
download | yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar.gz yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar.bz2 yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar.lz yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar.xz yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar.zst yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.zip |
Diffstat (limited to 'src/core/hle/svc.cpp')
-rw-r--r-- | src/core/hle/svc.cpp | 111 |
1 files changed, 109 insertions, 2 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index c05401143..e4b803046 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -25,6 +25,7 @@ #include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/session.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -237,7 +238,7 @@ static ResultCode SendSyncRequest(Kernel::Handle handle) { // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server // responds and cause a reschedule. - return session->SendSyncRequest(); + return session->SendSyncRequest(Kernel::GetCurrentThread()); } /// Close a handle @@ -398,6 +399,112 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha } } +/// In a single operation, sends a IPC reply and waits for a new request. +static ResultCode ReplyAndReceive(s32* index, Kernel::Handle* handles, s32 handle_count, + Kernel::Handle reply_target) { + // 'handles' has to be a valid pointer even if 'handle_count' is 0. + if (handles == nullptr) + return Kernel::ERR_INVALID_POINTER; + + // Check if 'handle_count' is invalid + if (handle_count < 0) + return Kernel::ERR_OUT_OF_RANGE; + + using ObjectPtr = SharedPtr<Kernel::WaitObject>; + std::vector<ObjectPtr> objects(handle_count); + + for (int i = 0; i < handle_count; ++i) { + auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]); + if (object == nullptr) + return ERR_INVALID_HANDLE; + objects[i] = object; + } + + // We are also sending a command reply. + // Do not send a reply if the command id in the command buffer is 0xFFFF. + u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::Header header{cmd_buff[0]}; + if (reply_target != 0 && header.command_id != 0xFFFF) { + auto session = Kernel::g_handle_table.Get<Kernel::ServerSession>(reply_target); + if (session == nullptr) + return ERR_INVALID_HANDLE; + + auto request_thread = std::move(session->currently_handling); + + // Mark the request as "handled". + session->currently_handling = nullptr; + + // Error out if there's no request thread or the session was closed. + // TODO(Subv): Is the same error code (ClosedByRemote) returned for both of these cases? + if (request_thread == nullptr || session->parent->client == nullptr) { + *index = -1; + return Kernel::ERR_SESSION_CLOSED_BY_REMOTE; + } + + // TODO(Subv): Perform IPC translation from the current thread to request_thread. + + // Note: The scheduler is not invoked here. + request_thread->ResumeFromWait(); + } + + if (handle_count == 0) { + *index = 0; + // The kernel uses this value as a placeholder for the real error, and returns it when we + // pass no handles and do not perform any reply. + if (reply_target == 0 || header.command_id == 0xFFFF) + return ResultCode(0xE7E3FFFF); + + return RESULT_SUCCESS; + } + + auto thread = Kernel::GetCurrentThread(); + + // Find the first object that is acquirable in the provided list of objects + auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { + return !object->ShouldWait(thread); + }); + + if (itr != objects.end()) { + // We found a ready object, acquire it and set the result value + Kernel::WaitObject* object = itr->get(); + object->Acquire(thread); + *index = std::distance(objects.begin(), itr); + + if (object->GetHandleType() == Kernel::HandleType::ServerSession) { + auto server_session = static_cast<Kernel::ServerSession*>(object); + if (server_session->parent->client == nullptr) + return Kernel::ERR_SESSION_CLOSED_BY_REMOTE; + + // TODO(Subv): Perform IPC translation from the ServerSession to the current thread. + } + return RESULT_SUCCESS; + } + + // No objects were ready to be acquired, prepare to suspend the thread. + + // TODO(Subv): Perform IPC translation upon wakeup. + + // Put the thread to sleep + thread->status = THREADSTATUS_WAIT_SYNCH_ANY; + + // Add the thread to each of the objects' waiting threads. + for (size_t i = 0; i < objects.size(); ++i) { + Kernel::WaitObject* object = objects[i].get(); + object->AddWaitingThread(thread); + } + + thread->wait_objects = std::move(objects); + + Core::System::GetInstance().PrepareReschedule(); + + // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a + // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error. + // By default the index is set to -1. + thread->wait_set_output = true; + *index = -1; + return RESULT_SUCCESS; +} + /// Create an address arbiter (to allocate access to shared resources) static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) { using Kernel::AddressArbiter; @@ -1163,7 +1270,7 @@ static const FunctionDef SVC_Table[] = { {0x4C, nullptr, "ReplyAndReceive2"}, {0x4D, nullptr, "ReplyAndReceive3"}, {0x4E, nullptr, "ReplyAndReceive4"}, - {0x4F, nullptr, "ReplyAndReceive"}, + {0x4F, HLE::Wrap<ReplyAndReceive>, "ReplyAndReceive"}, {0x50, nullptr, "BindInterrupt"}, {0x51, nullptr, "UnbindInterrupt"}, {0x52, nullptr, "InvalidateProcessDataCache"}, |