summaryrefslogtreecommitdiff
path: root/src/core/hle/svc.cpp
diff options
context:
space:
mode:
authorGravatar Sebastian Valle2017-06-29 17:05:22 -0500
committerGravatar GitHub2017-06-29 17:05:22 -0500
commit56d718b2a1d6385c88c2044f780280a5dfbc6072 (patch)
treea74b2c67bde47be93f2b2c3d55292bfbb421985a /src/core/hle/svc.cpp
parentMerge pull request #2809 from wwylele/texture-copy-fix (diff)
parentKernel/SVC: Pass the current thread as a parameter to ClientSession::SendSync... (diff)
downloadyuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar.gz
yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.tar.xz
yuzu-56d718b2a1d6385c88c2044f780280a5dfbc6072.zip
Merge pull request #2793 from Subv/replyandreceive
Kernel/SVC: Partially implemented svcReplyAndReceive
Diffstat (limited to 'src/core/hle/svc.cpp')
-rw-r--r--src/core/hle/svc.cpp111
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 @@
25#include "core/hle/kernel/semaphore.h" 25#include "core/hle/kernel/semaphore.h"
26#include "core/hle/kernel/server_port.h" 26#include "core/hle/kernel/server_port.h"
27#include "core/hle/kernel/server_session.h" 27#include "core/hle/kernel/server_session.h"
28#include "core/hle/kernel/session.h"
28#include "core/hle/kernel/shared_memory.h" 29#include "core/hle/kernel/shared_memory.h"
29#include "core/hle/kernel/thread.h" 30#include "core/hle/kernel/thread.h"
30#include "core/hle/kernel/timer.h" 31#include "core/hle/kernel/timer.h"
@@ -237,7 +238,7 @@ static ResultCode SendSyncRequest(Kernel::Handle handle) {
237 238
238 // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server 239 // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
239 // responds and cause a reschedule. 240 // responds and cause a reschedule.
240 return session->SendSyncRequest(); 241 return session->SendSyncRequest(Kernel::GetCurrentThread());
241} 242}
242 243
243/// Close a handle 244/// Close a handle
@@ -398,6 +399,112 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha
398 } 399 }
399} 400}
400 401
402/// In a single operation, sends a IPC reply and waits for a new request.
403static ResultCode ReplyAndReceive(s32* index, Kernel::Handle* handles, s32 handle_count,
404 Kernel::Handle reply_target) {
405 // 'handles' has to be a valid pointer even if 'handle_count' is 0.
406 if (handles == nullptr)
407 return Kernel::ERR_INVALID_POINTER;
408
409 // Check if 'handle_count' is invalid
410 if (handle_count < 0)
411 return Kernel::ERR_OUT_OF_RANGE;
412
413 using ObjectPtr = SharedPtr<Kernel::WaitObject>;
414 std::vector<ObjectPtr> objects(handle_count);
415
416 for (int i = 0; i < handle_count; ++i) {
417 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
418 if (object == nullptr)
419 return ERR_INVALID_HANDLE;
420 objects[i] = object;
421 }
422
423 // We are also sending a command reply.
424 // Do not send a reply if the command id in the command buffer is 0xFFFF.
425 u32* cmd_buff = Kernel::GetCommandBuffer();
426 IPC::Header header{cmd_buff[0]};
427 if (reply_target != 0 && header.command_id != 0xFFFF) {
428 auto session = Kernel::g_handle_table.Get<Kernel::ServerSession>(reply_target);
429 if (session == nullptr)
430 return ERR_INVALID_HANDLE;
431
432 auto request_thread = std::move(session->currently_handling);
433
434 // Mark the request as "handled".
435 session->currently_handling = nullptr;
436
437 // Error out if there's no request thread or the session was closed.
438 // TODO(Subv): Is the same error code (ClosedByRemote) returned for both of these cases?
439 if (request_thread == nullptr || session->parent->client == nullptr) {
440 *index = -1;
441 return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
442 }
443
444 // TODO(Subv): Perform IPC translation from the current thread to request_thread.
445
446 // Note: The scheduler is not invoked here.
447 request_thread->ResumeFromWait();
448 }
449
450 if (handle_count == 0) {
451 *index = 0;
452 // The kernel uses this value as a placeholder for the real error, and returns it when we
453 // pass no handles and do not perform any reply.
454 if (reply_target == 0 || header.command_id == 0xFFFF)
455 return ResultCode(0xE7E3FFFF);
456
457 return RESULT_SUCCESS;
458 }
459
460 auto thread = Kernel::GetCurrentThread();
461
462 // Find the first object that is acquirable in the provided list of objects
463 auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
464 return !object->ShouldWait(thread);
465 });
466
467 if (itr != objects.end()) {
468 // We found a ready object, acquire it and set the result value
469 Kernel::WaitObject* object = itr->get();
470 object->Acquire(thread);
471 *index = std::distance(objects.begin(), itr);
472
473 if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
474 auto server_session = static_cast<Kernel::ServerSession*>(object);
475 if (server_session->parent->client == nullptr)
476 return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
477
478 // TODO(Subv): Perform IPC translation from the ServerSession to the current thread.
479 }
480 return RESULT_SUCCESS;
481 }
482
483 // No objects were ready to be acquired, prepare to suspend the thread.
484
485 // TODO(Subv): Perform IPC translation upon wakeup.
486
487 // Put the thread to sleep
488 thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
489
490 // Add the thread to each of the objects' waiting threads.
491 for (size_t i = 0; i < objects.size(); ++i) {
492 Kernel::WaitObject* object = objects[i].get();
493 object->AddWaitingThread(thread);
494 }
495
496 thread->wait_objects = std::move(objects);
497
498 Core::System::GetInstance().PrepareReschedule();
499
500 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
501 // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error.
502 // By default the index is set to -1.
503 thread->wait_set_output = true;
504 *index = -1;
505 return RESULT_SUCCESS;
506}
507
401/// Create an address arbiter (to allocate access to shared resources) 508/// Create an address arbiter (to allocate access to shared resources)
402static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) { 509static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) {
403 using Kernel::AddressArbiter; 510 using Kernel::AddressArbiter;
@@ -1163,7 +1270,7 @@ static const FunctionDef SVC_Table[] = {
1163 {0x4C, nullptr, "ReplyAndReceive2"}, 1270 {0x4C, nullptr, "ReplyAndReceive2"},
1164 {0x4D, nullptr, "ReplyAndReceive3"}, 1271 {0x4D, nullptr, "ReplyAndReceive3"},
1165 {0x4E, nullptr, "ReplyAndReceive4"}, 1272 {0x4E, nullptr, "ReplyAndReceive4"},
1166 {0x4F, nullptr, "ReplyAndReceive"}, 1273 {0x4F, HLE::Wrap<ReplyAndReceive>, "ReplyAndReceive"},
1167 {0x50, nullptr, "BindInterrupt"}, 1274 {0x50, nullptr, "BindInterrupt"},
1168 {0x51, nullptr, "UnbindInterrupt"}, 1275 {0x51, nullptr, "UnbindInterrupt"},
1169 {0x52, nullptr, "InvalidateProcessDataCache"}, 1276 {0x52, nullptr, "InvalidateProcessDataCache"},