svc_session.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/scope_exit.h"
  4. #include "core/core.h"
  5. #include "core/hle/kernel/k_light_session.h"
  6. #include "core/hle/kernel/k_process.h"
  7. #include "core/hle/kernel/k_scoped_resource_reservation.h"
  8. #include "core/hle/kernel/k_server_port.h"
  9. #include "core/hle/kernel/k_session.h"
  10. #include "core/hle/kernel/svc.h"
  11. namespace Kernel::Svc {
  12. namespace {
  13. template <typename T>
  14. Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, uint64_t name) {
  15. auto& process = GetCurrentProcess(system.Kernel());
  16. auto& handle_table = process.GetHandleTable();
  17. // Declare the session we're going to allocate.
  18. T* session;
  19. // Reserve a new session from the process resource limit.
  20. // TODO: Dynamic resource limits
  21. KScopedResourceReservation session_reservation(std::addressof(process),
  22. LimitableResource::SessionCountMax);
  23. if (session_reservation.Succeeded()) {
  24. session = T::Create(system.Kernel());
  25. } else {
  26. R_THROW(ResultLimitReached);
  27. // // We couldn't reserve a session. Check that we support dynamically expanding the
  28. // // resource limit.
  29. // R_UNLESS(process.GetResourceLimit() ==
  30. // std::addressof(system.Kernel().GetSystemResourceLimit()), ResultLimitReached);
  31. // R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached());
  32. // // Try to allocate a session from unused slab memory.
  33. // session = T::CreateFromUnusedSlabMemory();
  34. // R_UNLESS(session != nullptr, ResultLimitReached);
  35. // ON_RESULT_FAILURE { session->Close(); };
  36. // // If we're creating a KSession, we want to add two KSessionRequests to the heap, to
  37. // // prevent request exhaustion.
  38. // // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's
  39. // // no reason to not do this statically.
  40. // if constexpr (std::same_as<T, KSession>) {
  41. // for (size_t i = 0; i < 2; i++) {
  42. // KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory();
  43. // R_UNLESS(request != nullptr, ResultLimitReached);
  44. // request->Close();
  45. // }
  46. // }
  47. // We successfully allocated a session, so add the object we allocated to the resource
  48. // limit.
  49. // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
  50. }
  51. // Check that we successfully created a session.
  52. R_UNLESS(session != nullptr, ResultOutOfResource);
  53. // Initialize the session.
  54. session->Initialize(nullptr, name);
  55. // Commit the session reservation.
  56. session_reservation.Commit();
  57. // Ensure that we clean up the session (and its only references are handle table) on function
  58. // end.
  59. SCOPE_EXIT {
  60. session->GetClientSession().Close();
  61. session->GetServerSession().Close();
  62. };
  63. // Register the session.
  64. T::Register(system.Kernel(), session);
  65. // Add the server session to the handle table.
  66. R_TRY(handle_table.Add(out_server, std::addressof(session->GetServerSession())));
  67. // Ensure that we maintain a clean handle state on exit.
  68. ON_RESULT_FAILURE {
  69. handle_table.Remove(*out_server);
  70. };
  71. // Add the client session to the handle table.
  72. R_RETURN(handle_table.Add(out_client, std::addressof(session->GetClientSession())));
  73. }
  74. } // namespace
  75. Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light,
  76. u64 name) {
  77. if (is_light) {
  78. R_RETURN(CreateSession<KLightSession>(system, out_server, out_client, name));
  79. } else {
  80. R_RETURN(CreateSession<KSession>(system, out_server, out_client, name));
  81. }
  82. }
  83. Result AcceptSession(Core::System& system, Handle* out, Handle port_handle) {
  84. // Get the current handle table.
  85. auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
  86. // Get the server port.
  87. KScopedAutoObject port = handle_table.GetObject<KServerPort>(port_handle);
  88. R_UNLESS(port.IsNotNull(), ResultInvalidHandle);
  89. // Reserve an entry for the new session.
  90. R_TRY(handle_table.Reserve(out));
  91. ON_RESULT_FAILURE {
  92. handle_table.Unreserve(*out);
  93. };
  94. // Accept the session.
  95. KAutoObject* session;
  96. if (port->IsLight()) {
  97. session = port->AcceptLightSession();
  98. } else {
  99. session = port->AcceptSession();
  100. }
  101. // Ensure we accepted successfully.
  102. R_UNLESS(session != nullptr, ResultNotFound);
  103. // Register the session.
  104. handle_table.Register(*out, session);
  105. session->Close();
  106. R_SUCCEED();
  107. }
  108. Result CreateSession64(Core::System& system, Handle* out_server_session_handle,
  109. Handle* out_client_session_handle, bool is_light, uint64_t name) {
  110. R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
  111. name));
  112. }
  113. Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port) {
  114. R_RETURN(AcceptSession(system, out_handle, port));
  115. }
  116. Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle,
  117. Handle* out_client_session_handle, bool is_light, uint32_t name) {
  118. R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
  119. name));
  120. }
  121. Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port) {
  122. R_RETURN(AcceptSession(system, out_handle, port));
  123. }
  124. } // namespace Kernel::Svc