| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include "common/scope_exit.h"
- #include "core/core.h"
- #include "core/hle/kernel/k_light_session.h"
- #include "core/hle/kernel/k_process.h"
- #include "core/hle/kernel/k_scoped_resource_reservation.h"
- #include "core/hle/kernel/k_server_port.h"
- #include "core/hle/kernel/k_session.h"
- #include "core/hle/kernel/svc.h"
- namespace Kernel::Svc {
- namespace {
- template <typename T>
- Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, uint64_t name) {
- auto& process = GetCurrentProcess(system.Kernel());
- auto& handle_table = process.GetHandleTable();
- // Declare the session we're going to allocate.
- T* session;
- // Reserve a new session from the process resource limit.
- // TODO: Dynamic resource limits
- KScopedResourceReservation session_reservation(std::addressof(process),
- LimitableResource::SessionCountMax);
- if (session_reservation.Succeeded()) {
- session = T::Create(system.Kernel());
- } else {
- R_THROW(ResultLimitReached);
- // // We couldn't reserve a session. Check that we support dynamically expanding the
- // // resource limit.
- // R_UNLESS(process.GetResourceLimit() ==
- // std::addressof(system.Kernel().GetSystemResourceLimit()), ResultLimitReached);
- // R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached());
- // // Try to allocate a session from unused slab memory.
- // session = T::CreateFromUnusedSlabMemory();
- // R_UNLESS(session != nullptr, ResultLimitReached);
- // ON_RESULT_FAILURE { session->Close(); };
- // // If we're creating a KSession, we want to add two KSessionRequests to the heap, to
- // // prevent request exhaustion.
- // // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's
- // // no reason to not do this statically.
- // if constexpr (std::same_as<T, KSession>) {
- // for (size_t i = 0; i < 2; i++) {
- // KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory();
- // R_UNLESS(request != nullptr, ResultLimitReached);
- // request->Close();
- // }
- // }
- // We successfully allocated a session, so add the object we allocated to the resource
- // limit.
- // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
- }
- // Check that we successfully created a session.
- R_UNLESS(session != nullptr, ResultOutOfResource);
- // Initialize the session.
- session->Initialize(nullptr, name);
- // Commit the session reservation.
- session_reservation.Commit();
- // Ensure that we clean up the session (and its only references are handle table) on function
- // end.
- SCOPE_EXIT {
- session->GetClientSession().Close();
- session->GetServerSession().Close();
- };
- // Register the session.
- T::Register(system.Kernel(), session);
- // Add the server session to the handle table.
- R_TRY(handle_table.Add(out_server, std::addressof(session->GetServerSession())));
- // Ensure that we maintain a clean handle state on exit.
- ON_RESULT_FAILURE {
- handle_table.Remove(*out_server);
- };
- // Add the client session to the handle table.
- R_RETURN(handle_table.Add(out_client, std::addressof(session->GetClientSession())));
- }
- } // namespace
- Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light,
- u64 name) {
- if (is_light) {
- R_RETURN(CreateSession<KLightSession>(system, out_server, out_client, name));
- } else {
- R_RETURN(CreateSession<KSession>(system, out_server, out_client, name));
- }
- }
- Result AcceptSession(Core::System& system, Handle* out, Handle port_handle) {
- // Get the current handle table.
- auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
- // Get the server port.
- KScopedAutoObject port = handle_table.GetObject<KServerPort>(port_handle);
- R_UNLESS(port.IsNotNull(), ResultInvalidHandle);
- // Reserve an entry for the new session.
- R_TRY(handle_table.Reserve(out));
- ON_RESULT_FAILURE {
- handle_table.Unreserve(*out);
- };
- // Accept the session.
- KAutoObject* session;
- if (port->IsLight()) {
- session = port->AcceptLightSession();
- } else {
- session = port->AcceptSession();
- }
- // Ensure we accepted successfully.
- R_UNLESS(session != nullptr, ResultNotFound);
- // Register the session.
- handle_table.Register(*out, session);
- session->Close();
- R_SUCCEED();
- }
- Result CreateSession64(Core::System& system, Handle* out_server_session_handle,
- Handle* out_client_session_handle, bool is_light, uint64_t name) {
- R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
- name));
- }
- Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port) {
- R_RETURN(AcceptSession(system, out_handle, port));
- }
- Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle,
- Handle* out_client_session_handle, bool is_light, uint32_t name) {
- R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
- name));
- }
- Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port) {
- R_RETURN(AcceptSession(system, out_handle, port));
- }
- } // namespace Kernel::Svc
|