summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Subv2017-06-20 19:27:20 -0500
committerGravatar Subv2017-06-25 23:38:28 -0500
commit88c93a7436ee744d61abaa7a3fb0fc59982b0a06 (patch)
tree19a06ba1030dc8a9a92b117fa18f841d8673d380
parentKernel/ServerSession: Keep track of which threads have issued sync requests. (diff)
downloadyuzu-88c93a7436ee744d61abaa7a3fb0fc59982b0a06.tar.gz
yuzu-88c93a7436ee744d61abaa7a3fb0fc59982b0a06.tar.xz
yuzu-88c93a7436ee744d61abaa7a3fb0fc59982b0a06.zip
Kernel/SVC: Partially implemented svcReplyAndReceive.
It behaves mostly as WaitSynchronizationN with wait_all = false, except for IPC buffer translation. The target thread of an IPC response will now wake up when responding. IPC buffer translation is currently not implemented. Error passing back to svcSendSyncRequest is currently not implemented.
-rw-r--r--src/core/hle/function_wrappers.h23
-rw-r--r--src/core/hle/svc.cpp109
2 files changed, 121 insertions, 11 deletions
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 18b6e7017..2abdfe1b3 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -16,9 +16,6 @@ namespace HLE {
16 16
17#define PARAM(n) Core::CPU().GetReg(n) 17#define PARAM(n) Core::CPU().GetReg(n)
18 18
19/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
20static const ResultCode RESULT_INVALID(0xDEADC0DE);
21
22/** 19/**
23 * HLE a function return from the current ARM11 userland process 20 * HLE a function return from the current ARM11 userland process
24 * @param res Result to return 21 * @param res Result to return
@@ -68,10 +65,18 @@ void Wrap() {
68 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))) 65 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)))
69 .raw; 66 .raw;
70 67
71 if (retval != RESULT_INVALID.raw) { 68 Core::CPU().SetReg(1, (u32)param_1);
72 Core::CPU().SetReg(1, (u32)param_1); 69 FuncReturn(retval);
73 FuncReturn(retval); 70}
74 } 71
72template <ResultCode func(s32*, u32*, s32, u32)>
73void Wrap() {
74 s32 param_1 = 0;
75 u32 retval =
76 func(&param_1, (Kernel::Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), PARAM(3)).raw;
77
78 Core::CPU().SetReg(1, (u32)param_1);
79 FuncReturn(retval);
75} 80}
76 81
77template <ResultCode func(u32, u32, u32, u32, s64)> 82template <ResultCode func(u32, u32, u32, u32, s64)>
@@ -92,9 +97,7 @@ template <ResultCode func(u32, s64)>
92void Wrap() { 97void Wrap() {
93 s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw; 98 s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw;
94 99
95 if (retval != RESULT_INVALID.raw) { 100 FuncReturn(retval);
96 FuncReturn(retval);
97 }
98} 101}
99 102
100template <ResultCode func(MemoryInfo*, PageInfo*, u32)> 103template <ResultCode func(MemoryInfo*, PageInfo*, u32)>
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index e68b9f16a..2cdbe3fb9 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"
@@ -397,6 +398,112 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha
397 } 398 }
398} 399}
399 400
401/// In a single operation, sends a IPC reply and waits for a new request.
402static ResultCode ReplyAndReceive(s32* index, Kernel::Handle* handles, s32 handle_count,
403 Kernel::Handle reply_target) {
404 // 'handles' has to be a valid pointer even if 'handle_count' is 0.
405 if (handles == nullptr)
406 return Kernel::ERR_INVALID_POINTER;
407
408 // Check if 'handle_count' is invalid
409 if (handle_count < 0)
410 return Kernel::ERR_OUT_OF_RANGE;
411
412 using ObjectPtr = SharedPtr<Kernel::WaitObject>;
413 std::vector<ObjectPtr> objects(handle_count);
414
415 for (int i = 0; i < handle_count; ++i) {
416 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
417 if (object == nullptr)
418 return ERR_INVALID_HANDLE;
419 objects[i] = object;
420 }
421
422 // We are also sending a command reply.
423 // Do not send a reply if the command id in the command buffer is 0xFFFF.
424 u32* cmd_buff = Kernel::GetCommandBuffer();
425 IPC::Header header{cmd_buff[0]};
426 if (reply_target != 0 && header.command_id != 0xFFFF) {
427 auto session = Kernel::g_handle_table.Get<Kernel::ServerSession>(reply_target);
428 if (session == nullptr)
429 return ERR_INVALID_HANDLE;
430
431 auto request_thread = std::move(session->currently_handling);
432
433 // Mark the request as "handled".
434 session->currently_handling = nullptr;
435
436 // Error out if there's no request thread or the session was closed.
437 // TODO(Subv): Is the same error code (ClosedByRemote) returned for both of these cases?
438 if (request_thread == nullptr || session->parent->client == nullptr) {
439 *index = -1;
440 return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
441 }
442
443 // TODO(Subv): Perform IPC translation from the current thread to request_thread.
444
445 // Note: The scheduler is not invoked here.
446 request_thread->ResumeFromWait();
447 }
448
449 if (handle_count == 0) {
450 *index = 0;
451 // The kernel uses this value as a placeholder for the real error, and returns it when we
452 // pass no handles and do not perform any reply.
453 if (reply_target == 0 || header.command_id == 0xFFFF)
454 return ResultCode(0xE7E3FFFF);
455
456 return RESULT_SUCCESS;
457 }
458
459 auto thread = Kernel::GetCurrentThread();
460
461 // Find the first object that is acquirable in the provided list of objects
462 auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
463 return !object->ShouldWait(thread);
464 });
465
466 if (itr != objects.end()) {
467 // We found a ready object, acquire it and set the result value
468 Kernel::WaitObject* object = itr->get();
469 object->Acquire(thread);
470 *index = std::distance(objects.begin(), itr);
471
472 if (object->GetHandleType() == Kernel::HandleType::ServerSession) {
473 auto server_session = static_cast<Kernel::ServerSession*>(object);
474 if (server_session->parent->client == nullptr)
475 return Kernel::ERR_SESSION_CLOSED_BY_REMOTE;
476
477 // TODO(Subv): Perform IPC translation from the ServerSession to the current thread.
478 }
479 return RESULT_SUCCESS;
480 }
481
482 // No objects were ready to be acquired, prepare to suspend the thread.
483
484 // TODO(Subv): Perform IPC translation upon wakeup.
485
486 // Put the thread to sleep
487 thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
488
489 // Add the thread to each of the objects' waiting threads.
490 for (size_t i = 0; i < objects.size(); ++i) {
491 Kernel::WaitObject* object = objects[i].get();
492 object->AddWaitingThread(thread);
493 }
494
495 thread->wait_objects = std::move(objects);
496
497 Core::System::GetInstance().PrepareReschedule();
498
499 // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
500 // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error.
501 // By default the index is set to -1.
502 thread->wait_set_output = true;
503 *index = -1;
504 return RESULT_SUCCESS;
505}
506
400/// Create an address arbiter (to allocate access to shared resources) 507/// Create an address arbiter (to allocate access to shared resources)
401static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) { 508static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) {
402 using Kernel::AddressArbiter; 509 using Kernel::AddressArbiter;
@@ -1128,7 +1235,7 @@ static const FunctionDef SVC_Table[] = {
1128 {0x4C, nullptr, "ReplyAndReceive2"}, 1235 {0x4C, nullptr, "ReplyAndReceive2"},
1129 {0x4D, nullptr, "ReplyAndReceive3"}, 1236 {0x4D, nullptr, "ReplyAndReceive3"},
1130 {0x4E, nullptr, "ReplyAndReceive4"}, 1237 {0x4E, nullptr, "ReplyAndReceive4"},
1131 {0x4F, nullptr, "ReplyAndReceive"}, 1238 {0x4F, HLE::Wrap<ReplyAndReceive>, "ReplyAndReceive"},
1132 {0x50, nullptr, "BindInterrupt"}, 1239 {0x50, nullptr, "BindInterrupt"},
1133 {0x51, nullptr, "UnbindInterrupt"}, 1240 {0x51, nullptr, "UnbindInterrupt"},
1134 {0x52, nullptr, "InvalidateProcessDataCache"}, 1241 {0x52, nullptr, "InvalidateProcessDataCache"},