diff options
Diffstat (limited to 'src/core/hle/service/sm')
-rw-r--r-- | src/core/hle/service/sm/controller.cpp | 22 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.cpp | 164 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.h | 35 |
3 files changed, 132 insertions, 89 deletions
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 916177efd..de530cbfb 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -5,16 +5,16 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/service/sm/controller.h" namespace Service::SM { void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); - LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); + LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); ctx.Session()->ConvertToDomain(); IPC::ResponseBuilder rb{ctx, 3}; @@ -26,15 +26,23 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong // and that we probably want to actually make an entirely new Session, but we still need to // verify this on hardware. + LOG_DEBUG(Service, "called"); + auto session = ctx.Session()->GetParent(); + + // Open a reference to the session to simulate a new one being created. + session->Open(); + session->GetClientSession().Open(); + session->GetServerSession().Open(); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(ctx.Session()->GetParent()->Client()); + rb.PushMoveObjects(session->GetClientSession()); } void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject"); + LOG_DEBUG(Service, "called"); CloneCurrentObject(ctx); } @@ -44,7 +52,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u16>(0x1000); + rb.Push<u16>(0x8000); } // https://switchbrew.org/wiki/IPC_Marshalling diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 94608d529..8cc9aee8a 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -6,15 +6,20 @@ #include "common/assert.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_port.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/result.h" #include "core/hle/service/sm/controller.h" #include "core/hle/service/sm/sm.h" namespace Service::SM { +constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2); constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); @@ -31,24 +36,21 @@ static ResultCode ValidateServiceName(const std::string& name) { LOG_ERROR(Service_SM, "Invalid service name! service={}", name); return ERR_INVALID_NAME; } - if (name.rfind('\0') != std::string::npos) { - LOG_ERROR(Service_SM, "A non null terminated service was passed"); - return ERR_INVALID_NAME; - } return RESULT_SUCCESS; } -void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) { - ASSERT(self->sm_interface.expired()); +Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) { + ASSERT(self.sm_interface.expired()); auto sm = std::make_shared<SM>(self, system); - sm->InstallAsNamedPort(system.Kernel()); - self->sm_interface = sm; - self->controller_interface = std::make_unique<Controller>(system); + self.sm_interface = sm; + self.controller_interface = std::make_unique<Controller>(system); + + return sm->CreatePort(system.Kernel()); } -ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name, - u32 max_sessions) { +ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, + u32 max_sessions) { CASCADE_CODE(ValidateServiceName(name)); @@ -57,11 +59,12 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(s return ERR_ALREADY_REGISTERED; } - auto [server_port, client_port] = - Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name); + auto* port = Kernel::KPort::Create(kernel); + port->Initialize(max_sessions, false, name); - registered_services.emplace(std::move(name), std::move(client_port)); - return MakeResult(std::move(server_port)); + registered_services.emplace(std::move(name), port); + + return MakeResult(&port->GetServerPort()); } ResultCode ServiceManager::UnregisterService(const std::string& name) { @@ -72,12 +75,14 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) { LOG_ERROR(Service_SM, "Server is not registered! service={}", name); return ERR_SERVICE_NOT_REGISTERED; } + + iter->second->Close(); + registered_services.erase(iter); return RESULT_SUCCESS; } -ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( - const std::string& name) { +ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) { CASCADE_CODE(ValidateServiceName(name)); auto it = registered_services.find(name); @@ -89,13 +94,6 @@ ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( return MakeResult(it->second); } -ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService( - const std::string& name) { - - CASCADE_RESULT(auto client_port, GetServicePort(name)); - return client_port->Connect(); -} - SM::~SM() = default; /** @@ -108,50 +106,81 @@ SM::~SM() = default; void SM::Initialize(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SM, "called"); + is_initialized = true; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void SM::GetService(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; + auto result = GetServiceImpl(ctx); + if (result.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(result.Code()); + rb.PushMoveObjects(result.Unwrap()); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result.Code()); + } +} + +void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) { + auto result = GetServiceImpl(ctx); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(result.Code()); + rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr); +} + +static std::string PopServiceName(IPC::RequestParser& rp) { auto name_buf = rp.PopRaw<std::array<char, 8>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + std::string result; + for (const auto& c : name_buf) { + if (c >= ' ' && c <= '~') { + result.push_back(c); + } + } + return result; +} - std::string name(name_buf.begin(), end); +ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) { + if (!is_initialized) { + return ERR_NOT_INITIALIZED; + } - auto client_port = service_manager->GetServicePort(name); - if (client_port.Failed()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(client_port.Code()); - LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); - if (name.length() == 0) - return; // LibNX Fix - UNIMPLEMENTED(); - return; + IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); + + auto result = service_manager.GetServicePort(name); + if (result.Failed()) { + LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); + return result.Code(); } - auto [client, server] = Kernel::Session::Create(kernel, name); + auto* port = result.Unwrap(); + + // Kernel::KScopedResourceReservation session_reservation( + // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); + // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); + + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(&port->GetClientPort(), std::move(name)); - const auto& server_port = client_port.Unwrap()->GetServerPort(); - if (server_port->GetHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(server); + // Commit the session reservation. + // session_reservation.Commit(); + + if (port->GetServerPort().GetHLEHandler()) { + port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); } else { - server_port->AppendPendingSession(server); + port->EnqueueSession(&session->GetServerSession()); } - LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); - IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; - rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(std::move(client)); + LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); + return MakeResult(&session->GetClientSession()); } void SM::RegisterService(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - - const auto name_buf = rp.PopRaw<std::array<char, 8>>(); - const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); - - const std::string name(name_buf.begin(), end); + std::string name(PopServiceName(rp)); const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); const auto max_session_count = rp.PopRaw<u32>(); @@ -159,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, max_session_count, is_light); - auto handle = service_manager->RegisterService(name, max_session_count); + auto handle = service_manager.RegisterService(name, max_session_count); if (handle.Failed()) { LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", handle.Code().raw); @@ -170,33 +199,38 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(handle.Code()); - rb.PushMoveObjects(std::move(handle).Unwrap()); + + auto server_port = handle.Unwrap(); + rb.PushMoveObjects(server_port); } void SM::UnregisterService(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); - const auto name_buf = rp.PopRaw<std::array<char, 8>>(); - const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); - - const std::string name(name_buf.begin(), end); LOG_DEBUG(Service_SM, "called with name={}", name); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(service_manager->UnregisterService(name)); + rb.Push(service_manager.UnregisterService(name)); } -SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_) +SM::SM(ServiceManager& service_manager_, Core::System& system_) : ServiceFramework{system_, "sm:", 4}, - service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { - static const FunctionInfo functions[] = { + service_manager{service_manager_}, kernel{system_.Kernel()} { + RegisterHandlers({ {0, &SM::Initialize, "Initialize"}, {1, &SM::GetService, "GetService"}, {2, &SM::RegisterService, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, {4, nullptr, "DetachClient"}, - }; - RegisterHandlers(functions); + }); + RegisterHandlersTipc({ + {0, &SM::Initialize, "Initialize"}, + {1, &SM::GetServiceTipc, "GetService"}, + {2, &SM::RegisterService, "RegisterService"}, + {3, &SM::UnregisterService, "UnregisterService"}, + {4, nullptr, "DetachClient"}, + }); } } // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 3f46ae44f..60f0b3f8a 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -10,9 +10,7 @@ #include <unordered_map> #include "common/concepts.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/k_port.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -21,10 +19,11 @@ class System; } namespace Kernel { -class ClientPort; -class ClientSession; +class KClientPort; +class KClientSession; class KernelCore; -class ServerPort; +class KPort; +class KServerPort; class SessionRequestHandler; } // namespace Kernel @@ -35,31 +34,33 @@ class Controller; /// Interface to "sm:" service class SM final : public ServiceFramework<SM> { public: - explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_); + explicit SM(ServiceManager& service_manager_, Core::System& system_); ~SM() override; private: void Initialize(Kernel::HLERequestContext& ctx); void GetService(Kernel::HLERequestContext& ctx); + void GetServiceTipc(Kernel::HLERequestContext& ctx); void RegisterService(Kernel::HLERequestContext& ctx); void UnregisterService(Kernel::HLERequestContext& ctx); - std::shared_ptr<ServiceManager> service_manager; + ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx); + + ServiceManager& service_manager; + bool is_initialized{}; Kernel::KernelCore& kernel; }; class ServiceManager { public: - static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system); + static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); - ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name, - u32 max_sessions); + ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions); ResultCode UnregisterService(const std::string& name); - ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); - ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); + ResultVal<Kernel::KPort*> GetServicePort(const std::string& name); template <Common::DerivedFrom<Kernel::SessionRequestHandler> T> std::shared_ptr<T> GetService(const std::string& service_name) const { @@ -68,11 +69,11 @@ public: LOG_DEBUG(Service, "Can't find service: {}", service_name); return nullptr; } - auto port = service->second->GetServerPort(); + auto* port = service->second; if (port == nullptr) { return nullptr; } - return std::static_pointer_cast<T>(port->GetHLEHandler()); + return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler()); } void InvokeControlRequest(Kernel::HLERequestContext& context); @@ -81,8 +82,8 @@ private: std::weak_ptr<SM> sm_interface; std::unique_ptr<Controller> controller_interface; - /// Map of registered services, retrieved using GetServicePort or ConnectToService. - std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services; + /// Map of registered services, retrieved using GetServicePort. + std::unordered_map<std::string, Kernel::KPort*> registered_services; /// Kernel context Kernel::KernelCore& kernel; |