summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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"},