summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp170
1 files changed, 156 insertions, 14 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 27e5a805d..510a9b3e3 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -29,6 +29,7 @@
29#include "core/hle/kernel/k_resource_limit.h" 29#include "core/hle/kernel/k_resource_limit.h"
30#include "core/hle/kernel/k_scheduler.h" 30#include "core/hle/kernel/k_scheduler.h"
31#include "core/hle/kernel/k_scoped_resource_reservation.h" 31#include "core/hle/kernel/k_scoped_resource_reservation.h"
32#include "core/hle/kernel/k_session.h"
32#include "core/hle/kernel/k_shared_memory.h" 33#include "core/hle/kernel/k_shared_memory.h"
33#include "core/hle/kernel/k_synchronization_object.h" 34#include "core/hle/kernel/k_synchronization_object.h"
34#include "core/hle/kernel/k_thread.h" 35#include "core/hle/kernel/k_thread.h"
@@ -256,6 +257,93 @@ static Result UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u3
256 return UnmapMemory(system, dst_addr, src_addr, size); 257 return UnmapMemory(system, dst_addr, src_addr, size);
257} 258}
258 259
260template <typename T>
261Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, u64 name) {
262 auto& process = *system.CurrentProcess();
263 auto& handle_table = process.GetHandleTable();
264
265 // Declare the session we're going to allocate.
266 T* session;
267
268 // Reserve a new session from the process resource limit.
269 // FIXME: LimitableResource_SessionCountMax
270 KScopedResourceReservation session_reservation(&process, LimitableResource::Sessions);
271 if (session_reservation.Succeeded()) {
272 session = T::Create(system.Kernel());
273 } else {
274 return ResultLimitReached;
275
276 // // We couldn't reserve a session. Check that we support dynamically expanding the
277 // // resource limit.
278 // R_UNLESS(process.GetResourceLimit() ==
279 // &system.Kernel().GetSystemResourceLimit(), ResultLimitReached);
280 // R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached());
281
282 // // Try to allocate a session from unused slab memory.
283 // session = T::CreateFromUnusedSlabMemory();
284 // R_UNLESS(session != nullptr, ResultLimitReached);
285 // ON_RESULT_FAILURE { session->Close(); };
286
287 // // If we're creating a KSession, we want to add two KSessionRequests to the heap, to
288 // // prevent request exhaustion.
289 // // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's
290 // // no reason to not do this statically.
291 // if constexpr (std::same_as<T, KSession>) {
292 // for (size_t i = 0; i < 2; i++) {
293 // KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory();
294 // R_UNLESS(request != nullptr, ResultLimitReached);
295 // request->Close();
296 // }
297 // }
298
299 // We successfully allocated a session, so add the object we allocated to the resource
300 // limit.
301 // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::Sessions, 1);
302 }
303
304 // Check that we successfully created a session.
305 R_UNLESS(session != nullptr, ResultOutOfResource);
306
307 // Initialize the session.
308 session->Initialize(nullptr, fmt::format("{}", name));
309
310 // Commit the session reservation.
311 session_reservation.Commit();
312
313 // Ensure that we clean up the session (and its only references are handle table) on function
314 // end.
315 SCOPE_EXIT({
316 session->GetClientSession().Close();
317 session->GetServerSession().Close();
318 });
319
320 // Register the session.
321 T::Register(system.Kernel(), session);
322
323 // Add the server session to the handle table.
324 R_TRY(handle_table.Add(out_server, &session->GetServerSession()));
325
326 // Add the client session to the handle table.
327 const auto result = handle_table.Add(out_client, &session->GetClientSession());
328
329 if (!R_SUCCEEDED(result)) {
330 // Ensure that we maintaing a clean handle state on exit.
331 handle_table.Remove(*out_server);
332 }
333
334 return result;
335}
336
337static Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client,
338 u32 is_light, u64 name) {
339 if (is_light) {
340 // return CreateSession<KLightSession>(system, out_server, out_client, name);
341 return ResultUnknown;
342 } else {
343 return CreateSession<KSession>(system, out_server, out_client, name);
344 }
345}
346
259/// Connect to an OS service given the port name, returns the handle to the port to out 347/// Connect to an OS service given the port name, returns the handle to the port to out
260static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) { 348static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) {
261 auto& memory = system.Memory(); 349 auto& memory = system.Memory();
@@ -295,7 +383,8 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n
295 383
296 // Create a session. 384 // Create a session.
297 KClientSession* session{}; 385 KClientSession* session{};
298 R_TRY(port->CreateSession(std::addressof(session))); 386 R_TRY(port->CreateSession(std::addressof(session),
387 std::make_shared<SessionRequestManager>(kernel)));
299 port->Close(); 388 port->Close();
300 389
301 // Register the session in the table, close the extra reference. 390 // Register the session in the table, close the extra reference.
@@ -313,7 +402,7 @@ static Result ConnectToNamedPort32(Core::System& system, Handle* out_handle,
313 return ConnectToNamedPort(system, out_handle, port_name_address); 402 return ConnectToNamedPort(system, out_handle, port_name_address);
314} 403}
315 404
316/// Makes a blocking IPC call to an OS service. 405/// Makes a blocking IPC call to a service.
317static Result SendSyncRequest(Core::System& system, Handle handle) { 406static Result SendSyncRequest(Core::System& system, Handle handle) {
318 auto& kernel = system.Kernel(); 407 auto& kernel = system.Kernel();
319 408
@@ -327,22 +416,75 @@ static Result SendSyncRequest(Core::System& system, Handle handle) {
327 416
328 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); 417 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
329 418
330 { 419 return session->SendSyncRequest();
331 KScopedSchedulerLock lock(kernel);
332
333 // This is a synchronous request, so we should wait for our request to complete.
334 GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue));
335 GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
336 session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming());
337 }
338
339 return GetCurrentThread(kernel).GetWaitResult();
340} 420}
341 421
342static Result SendSyncRequest32(Core::System& system, Handle handle) { 422static Result SendSyncRequest32(Core::System& system, Handle handle) {
343 return SendSyncRequest(system, handle); 423 return SendSyncRequest(system, handle);
344} 424}
345 425
426static Result ReplyAndReceive(Core::System& system, s32* out_index, Handle* handles,
427 s32 num_handles, Handle reply_target, s64 timeout_ns) {
428 auto& kernel = system.Kernel();
429 auto& handle_table = GetCurrentThread(kernel).GetOwnerProcess()->GetHandleTable();
430
431 // Convert handle list to object table.
432 std::vector<KSynchronizationObject*> objs(num_handles);
433 R_UNLESS(
434 handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, num_handles),
435 ResultInvalidHandle);
436
437 // Ensure handles are closed when we're done.
438 SCOPE_EXIT({
439 for (auto i = 0; i < num_handles; ++i) {
440 objs[i]->Close();
441 }
442 });
443
444 // Reply to the target, if one is specified.
445 if (reply_target != InvalidHandle) {
446 KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target);
447 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
448
449 // If we fail to reply, we want to set the output index to -1.
450 // ON_RESULT_FAILURE { *out_index = -1; };
451
452 // Send the reply.
453 // R_TRY(session->SendReply());
454
455 Result rc = session->SendReply();
456 if (!R_SUCCEEDED(rc)) {
457 *out_index = -1;
458 return rc;
459 }
460 }
461
462 // Wait for a message.
463 while (true) {
464 // Wait for an object.
465 s32 index;
466 Result result = KSynchronizationObject::Wait(kernel, &index, objs.data(),
467 static_cast<s32>(objs.size()), timeout_ns);
468 if (result == ResultTimedOut) {
469 return result;
470 }
471
472 // Receive the request.
473 if (R_SUCCEEDED(result)) {
474 KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
475 if (session != nullptr) {
476 result = session->ReceiveRequest();
477 if (result == ResultNotFound) {
478 continue;
479 }
480 }
481 }
482
483 *out_index = index;
484 return result;
485 }
486}
487
346/// Get the ID for the specified thread. 488/// Get the ID for the specified thread.
347static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { 489static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
348 // Get the thread from its handle. 490 // Get the thread from its handle.
@@ -2860,10 +3002,10 @@ static const FunctionDef SVC_Table_64[] = {
2860 {0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"}, 3002 {0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"},
2861 {0x3E, nullptr, "Unknown3e"}, 3003 {0x3E, nullptr, "Unknown3e"},
2862 {0x3F, nullptr, "Unknown3f"}, 3004 {0x3F, nullptr, "Unknown3f"},
2863 {0x40, nullptr, "CreateSession"}, 3005 {0x40, SvcWrap64<CreateSession>, "CreateSession"},
2864 {0x41, nullptr, "AcceptSession"}, 3006 {0x41, nullptr, "AcceptSession"},
2865 {0x42, nullptr, "ReplyAndReceiveLight"}, 3007 {0x42, nullptr, "ReplyAndReceiveLight"},
2866 {0x43, nullptr, "ReplyAndReceive"}, 3008 {0x43, SvcWrap64<ReplyAndReceive>, "ReplyAndReceive"},
2867 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, 3009 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
2868 {0x45, SvcWrap64<CreateEvent>, "CreateEvent"}, 3010 {0x45, SvcWrap64<CreateEvent>, "CreateEvent"},
2869 {0x46, nullptr, "MapIoRegion"}, 3011 {0x46, nullptr, "MapIoRegion"},