From 1eee09f36458bbb98212e05cb549cc43a995f03b Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 5 Jun 2017 22:18:19 -0700 Subject: Service: Move SRV interface to a new sm/ subdirectory This will contain the implementation of the sm (Service Manager) system module. --- src/core/CMakeLists.txt | 4 +- src/core/hle/service/service.cpp | 4 +- src/core/hle/service/sm/srv.cpp | 188 +++++++++++++++++++++++++++++++++++++++ src/core/hle/service/sm/srv.h | 25 ++++++ src/core/hle/service/srv.cpp | 188 --------------------------------------- src/core/hle/service/srv.h | 24 ----- 6 files changed, 217 insertions(+), 216 deletions(-) create mode 100644 src/core/hle/service/sm/srv.cpp create mode 100644 src/core/hle/service/sm/srv.h delete mode 100644 src/core/hle/service/srv.cpp delete mode 100644 src/core/hle/service/srv.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 51ee80bc4..0e2aacde7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -156,8 +156,8 @@ set(SRCS hle/service/qtm/qtm_sp.cpp hle/service/qtm/qtm_u.cpp hle/service/service.cpp + hle/service/sm/srv.cpp hle/service/soc_u.cpp - hle/service/srv.cpp hle/service/ssl_c.cpp hle/service/y2r_u.cpp hle/shared_page.cpp @@ -352,8 +352,8 @@ set(HEADERS hle/service/qtm/qtm_sp.h hle/service/qtm/qtm_u.h hle/service/service.h + hle/service/sm/srv.h hle/service/soc_u.h - hle/service/srv.h hle/service/ssl_c.h hle/service/y2r_u.h hle/shared_page.h diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 8f7c97d54..3a821871f 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -38,8 +38,8 @@ #include "core/hle/service/ptm/ptm.h" #include "core/hle/service/qtm/qtm.h" #include "core/hle/service/service.h" +#include "core/hle/service/sm/srv.h" #include "core/hle/service/soc_u.h" -#include "core/hle/service/srv.h" #include "core/hle/service/ssl_c.h" #include "core/hle/service/y2r_u.h" @@ -126,7 +126,7 @@ void AddService(Interface* interface_) { /// Initialize ServiceManager void Init() { - AddNamedPort(new SRV::SRV); + AddNamedPort(new SM::SRV); AddNamedPort(new ERR::ERR_F); FS::ArchiveInit(); diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp new file mode 100644 index 000000000..9d7a83597 --- /dev/null +++ b/src/core/hle/service/sm/srv.cpp @@ -0,0 +1,188 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/server_session.h" +#include "core/hle/service/sm/srv.h" + +namespace Service { +namespace SM { + +static Kernel::SharedPtr event_handle; + +/** + * SRV::RegisterClient service function + * Inputs: + * 0: 0x00010002 + * 1: ProcessId Header (must be 0x20) + * Outputs: + * 0: 0x00010040 + * 1: ResultCode + */ +static void RegisterClient(Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + if (cmd_buff[1] != IPC::CallingPidDesc()) { + cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); // 0x40 + cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; + return; + } + cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); // 0x10040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called"); +} + +/** + * SRV::EnableNotification service function + * Inputs: + * 0: 0x00020000 + * Outputs: + * 0: 0x00020042 + * 1: ResultCode + * 2: Translation descriptor: 0x20 + * 3: Handle to semaphore signaled on process notification + */ +static void EnableNotification(Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(bunnei): Change to a semaphore once these have been implemented + event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); + event_handle->Clear(); + + cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = IPC::CopyHandleDesc(1); + cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); + LOG_WARNING(Service_SRV, "(STUBBED) called"); +} + +/** + * SRV::GetServiceHandle service function + * Inputs: + * 0: 0x00050100 + * 1-2: 8-byte UTF-8 service name + * 3: Name length + * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) + * Outputs: + * 1: ResultCode + * 3: Service handle + */ +static void GetServiceHandle(Interface* self) { + ResultCode res = RESULT_SUCCESS; + u32* cmd_buff = Kernel::GetCommandBuffer(); + + std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); + auto it = Service::g_srv_services.find(port_name); + + if (it != Service::g_srv_services.end()) { + auto client_port = it->second; + + auto client_session = client_port->Connect(); + res = client_session.Code(); + + if (client_session.Succeeded()) { + // Return the client session + cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); + } + LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); + } else { + LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); + res = UnimplementedFunction(ErrorModule::SRV); + } + cmd_buff[1] = res.raw; +} + +/** + * SRV::Subscribe service function + * Inputs: + * 0: 0x00090040 + * 1: Notification ID + * Outputs: + * 0: 0x00090040 + * 1: ResultCode + */ +static void Subscribe(Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notification_id = cmd_buff[1]; + + cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); +} + +/** + * SRV::Unsubscribe service function + * Inputs: + * 0: 0x000A0040 + * 1: Notification ID + * Outputs: + * 0: 0x000A0040 + * 1: ResultCode + */ +static void Unsubscribe(Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notification_id = cmd_buff[1]; + + cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); +} + +/** + * SRV::PublishToSubscriber service function + * Inputs: + * 0: 0x000C0080 + * 1: Notification ID + * 2: Flags (bit0: only fire if not fired, bit1: report errors) + * Outputs: + * 0: 0x000C0040 + * 1: ResultCode + */ +static void PublishToSubscriber(Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notification_id = cmd_buff[1]; + u8 flags = cmd_buff[2] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, + flags); +} + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010002, RegisterClient, "RegisterClient"}, + {0x00020000, EnableNotification, "EnableNotification"}, + {0x00030100, nullptr, "RegisterService"}, + {0x000400C0, nullptr, "UnregisterService"}, + {0x00050100, GetServiceHandle, "GetServiceHandle"}, + {0x000600C2, nullptr, "RegisterPort"}, + {0x000700C0, nullptr, "UnregisterPort"}, + {0x00080100, nullptr, "GetPort"}, + {0x00090040, Subscribe, "Subscribe"}, + {0x000A0040, Unsubscribe, "Unsubscribe"}, + {0x000B0000, nullptr, "ReceiveNotification"}, + {0x000C0080, PublishToSubscriber, "PublishToSubscriber"}, + {0x000D0040, nullptr, "PublishAndGetSubscriber"}, + {0x000E00C0, nullptr, "IsServiceRegistered"}, +}; + +SRV::SRV() { + Register(FunctionTable); + event_handle = nullptr; +} + +SRV::~SRV() { + event_handle = nullptr; +} + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h new file mode 100644 index 000000000..4196ca1e2 --- /dev/null +++ b/src/core/hle/service/sm/srv.h @@ -0,0 +1,25 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "core/hle/service/service.h" + +namespace Service { +namespace SM { + +/// Interface to "srv:" service +class SRV final : public Interface { +public: + SRV(); + ~SRV() override; + + std::string GetPortName() const override { + return "srv:"; + } +}; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp deleted file mode 100644 index 130c9d25e..000000000 --- a/src/core/hle/service/srv.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include - -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/service/srv.h" - -namespace Service { -namespace SRV { - -static Kernel::SharedPtr event_handle; - -/** - * SRV::RegisterClient service function - * Inputs: - * 0: 0x00010002 - * 1: ProcessId Header (must be 0x20) - * Outputs: - * 0: 0x00010040 - * 1: ResultCode - */ -static void RegisterClient(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - if (cmd_buff[1] != IPC::CallingPidDesc()) { - cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); // 0x40 - cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; - return; - } - cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); // 0x10040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called"); -} - -/** - * SRV::EnableNotification service function - * Inputs: - * 0: 0x00020000 - * Outputs: - * 0: 0x00020042 - * 1: ResultCode - * 2: Translation descriptor: 0x20 - * 3: Handle to semaphore signaled on process notification - */ -static void EnableNotification(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(bunnei): Change to a semaphore once these have been implemented - event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); - event_handle->Clear(); - - cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - cmd_buff[2] = IPC::CopyHandleDesc(1); - cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); - LOG_WARNING(Service_SRV, "(STUBBED) called"); -} - -/** - * SRV::GetServiceHandle service function - * Inputs: - * 0: 0x00050100 - * 1-2: 8-byte UTF-8 service name - * 3: Name length - * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) - * Outputs: - * 1: ResultCode - * 3: Service handle - */ -static void GetServiceHandle(Interface* self) { - ResultCode res = RESULT_SUCCESS; - u32* cmd_buff = Kernel::GetCommandBuffer(); - - std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); - auto it = Service::g_srv_services.find(port_name); - - if (it != Service::g_srv_services.end()) { - auto client_port = it->second; - - auto client_session = client_port->Connect(); - res = client_session.Code(); - - if (client_session.Succeeded()) { - // Return the client session - cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); - } - LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); - } else { - LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); - res = UnimplementedFunction(ErrorModule::SRV); - } - cmd_buff[1] = res.raw; -} - -/** - * SRV::Subscribe service function - * Inputs: - * 0: 0x00090040 - * 1: Notification ID - * Outputs: - * 0: 0x00090040 - * 1: ResultCode - */ -static void Subscribe(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - u32 notification_id = cmd_buff[1]; - - cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); -} - -/** - * SRV::Unsubscribe service function - * Inputs: - * 0: 0x000A0040 - * 1: Notification ID - * Outputs: - * 0: 0x000A0040 - * 1: ResultCode - */ -static void Unsubscribe(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - u32 notification_id = cmd_buff[1]; - - cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); -} - -/** - * SRV::PublishToSubscriber service function - * Inputs: - * 0: 0x000C0080 - * 1: Notification ID - * 2: Flags (bit0: only fire if not fired, bit1: report errors) - * Outputs: - * 0: 0x000C0040 - * 1: ResultCode - */ -static void PublishToSubscriber(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - u32 notification_id = cmd_buff[1]; - u8 flags = cmd_buff[2] & 0xFF; - - cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 - cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, - flags); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010002, RegisterClient, "RegisterClient"}, - {0x00020000, EnableNotification, "EnableNotification"}, - {0x00030100, nullptr, "RegisterService"}, - {0x000400C0, nullptr, "UnregisterService"}, - {0x00050100, GetServiceHandle, "GetServiceHandle"}, - {0x000600C2, nullptr, "RegisterPort"}, - {0x000700C0, nullptr, "UnregisterPort"}, - {0x00080100, nullptr, "GetPort"}, - {0x00090040, Subscribe, "Subscribe"}, - {0x000A0040, Unsubscribe, "Unsubscribe"}, - {0x000B0000, nullptr, "ReceiveNotification"}, - {0x000C0080, PublishToSubscriber, "PublishToSubscriber"}, - {0x000D0040, nullptr, "PublishAndGetSubscriber"}, - {0x000E00C0, nullptr, "IsServiceRegistered"}, -}; - -SRV::SRV() { - Register(FunctionTable); - event_handle = nullptr; -} - -SRV::~SRV() { - event_handle = nullptr; -} - -} // namespace SRV -} // namespace Service diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h deleted file mode 100644 index d3a9de879..000000000 --- a/src/core/hle/service/srv.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -namespace Service { -namespace SRV { - -/// Interface to "srv:" service -class SRV final : public Interface { -public: - SRV(); - ~SRV() override; - - std::string GetPortName() const override { - return "srv:"; - } -}; - -} // namespace SRV -} // namespace Service -- cgit v1.2.3 From e5a59ef27c6a1fc66dfcbc63c84ad14dc73c54ae Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 5 Jun 2017 22:25:22 -0700 Subject: Service/sm: Use an actual semaphore for the notification semaphore An Event was used way back then when we didn't have proper working semaphores. Our Semaphore implementation is good enough now. --- src/core/hle/service/sm/srv.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp index 9d7a83597..d6946c734 100644 --- a/src/core/hle/service/sm/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -7,14 +7,16 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/event.h" +#include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/server_session.h" #include "core/hle/service/sm/srv.h" namespace Service { namespace SM { -static Kernel::SharedPtr event_handle; +constexpr int MAX_PENDING_NOTIFICATIONS = 16; + +static Kernel::SharedPtr notification_semaphore; /** * SRV::RegisterClient service function @@ -51,14 +53,13 @@ static void RegisterClient(Interface* self) { static void EnableNotification(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - // TODO(bunnei): Change to a semaphore once these have been implemented - event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); - event_handle->Clear(); + notification_semaphore = + Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap(); cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = IPC::CopyHandleDesc(1); - cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table.Create(notification_semaphore).MoveFrom(); LOG_WARNING(Service_SRV, "(STUBBED) called"); } @@ -177,11 +178,11 @@ const Interface::FunctionInfo FunctionTable[] = { SRV::SRV() { Register(FunctionTable); - event_handle = nullptr; + notification_semaphore = nullptr; } SRV::~SRV() { - event_handle = nullptr; + notification_semaphore = nullptr; } } // namespace SM -- cgit v1.2.3 From 23ec6b3d8f33e2e0d76e646049f1fc1d36e70cf3 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 5 Jun 2017 23:31:59 -0700 Subject: Service: Make service registration part of the sm implementation Also enhances the GetServiceHandle implementation to be more accurate. --- src/core/CMakeLists.txt | 2 ++ src/core/hle/service/service.cpp | 15 +++++------ src/core/hle/service/service.h | 2 -- src/core/hle/service/sm/sm.cpp | 58 ++++++++++++++++++++++++++++++++++++++++ src/core/hle/service/sm/sm.h | 49 +++++++++++++++++++++++++++++++++ src/core/hle/service/sm/srv.cpp | 45 +++++++++++++++++++++---------- 6 files changed, 147 insertions(+), 24 deletions(-) create mode 100644 src/core/hle/service/sm/sm.cpp create mode 100644 src/core/hle/service/sm/sm.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0e2aacde7..6e602b0c5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -156,6 +156,7 @@ set(SRCS hle/service/qtm/qtm_sp.cpp hle/service/qtm/qtm_u.cpp hle/service/service.cpp + hle/service/sm/sm.cpp hle/service/sm/srv.cpp hle/service/soc_u.cpp hle/service/ssl_c.cpp @@ -352,6 +353,7 @@ set(HEADERS hle/service/qtm/qtm_sp.h hle/service/qtm/qtm_u.h hle/service/service.h + hle/service/sm/sm.h hle/service/sm/srv.h hle/service/soc_u.h hle/service/ssl_c.h diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 3a821871f..1b64ee77d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -38,6 +38,7 @@ #include "core/hle/service/ptm/ptm.h" #include "core/hle/service/qtm/qtm.h" #include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/srv.h" #include "core/hle/service/soc_u.h" #include "core/hle/service/ssl_c.h" @@ -46,7 +47,6 @@ namespace Service { std::unordered_map> g_kernel_named_ports; -std::unordered_map> g_srv_services; /** * Creates a function string for logging, complete with the name (or header code, depending @@ -115,17 +115,16 @@ static void AddNamedPort(Interface* interface_) { } void AddService(Interface* interface_) { - Kernel::SharedPtr server_port; - Kernel::SharedPtr client_port; - std::tie(server_port, client_port) = - Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); - + auto server_port = + SM::g_service_manager + ->RegisterService(interface_->GetPortName(), interface_->GetMaxSessions()) + .MoveFrom(); server_port->SetHleHandler(std::shared_ptr(interface_)); - g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); } /// Initialize ServiceManager void Init() { + SM::g_service_manager = std::make_unique(); AddNamedPort(new SM::SRV); AddNamedPort(new ERR::ERR_F); @@ -187,7 +186,7 @@ void Shutdown() { AC::Shutdown(); FS::ArchiveShutdown(); - g_srv_services.clear(); + SM::g_service_manager = nullptr; g_kernel_named_ports.clear(); LOG_DEBUG(Service, "shutdown OK"); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index a5fe843f6..7010b116b 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -107,8 +107,6 @@ void Shutdown(); /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. extern std::unordered_map> g_kernel_named_ports; -/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map> g_srv_services; /// Adds a service to the services table void AddService(Interface* interface_); diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp new file mode 100644 index 000000000..40df0f0dd --- /dev/null +++ b/src/core/hle/service/sm/sm.cpp @@ -0,0 +1,58 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_port.h" +#include "core/hle/result.h" +#include "core/hle/service/sm/sm.h" + +namespace Service { +namespace SM { + +static ResultCode ValidateServiceName(const std::string& name) { + if (name.size() <= 0 || name.size() > 8) { + return ERR_INVALID_NAME_SIZE; + } + if (name.find('\0') != std::string::npos) { + return ERR_NAME_CONTAINS_NUL; + } + return RESULT_SUCCESS; +} + +ResultVal> ServiceManager::RegisterService( + std::string name, unsigned int max_sessions) { + + CASCADE_CODE(ValidateServiceName(name)); + Kernel::SharedPtr server_port; + Kernel::SharedPtr client_port; + std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); + + registered_services.emplace(name, std::move(client_port)); + return MakeResult>(std::move(server_port)); +} + +ResultVal> ServiceManager::GetServicePort( + const std::string& name) { + + CASCADE_CODE(ValidateServiceName(name)); + auto it = registered_services.find(name); + if (it == registered_services.end()) { + return ERR_SERVICE_NOT_REGISTERED; + } + + return MakeResult>(it->second); +} + +ResultVal> ServiceManager::ConnectToService( + const std::string& name) { + + CASCADE_RESULT(auto client_port, GetServicePort(name)); + return client_port->Connect(); +} + +std::unique_ptr g_service_manager; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h new file mode 100644 index 000000000..5fac5455c --- /dev/null +++ b/src/core/hle/service/sm/sm.h @@ -0,0 +1,49 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class ClientPort; +class ClientSession; +class ServerPort; +class SessionRequestHandler; +} // namespace Kernel + +namespace Service { +namespace SM { + +constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(1, ErrorModule::SRV, ErrorSummary::WouldBlock, + ErrorLevel::Temporary); // 0xD0406401 +constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(2, ErrorModule::SRV, ErrorSummary::WouldBlock, + ErrorLevel::Temporary); // 0xD0406402 +constexpr ResultCode ERR_INVALID_NAME_SIZE(5, ErrorModule::SRV, ErrorSummary::WrongArgument, + ErrorLevel::Permanent); // 0xD9006405 +constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::InvalidArgument, + ErrorLevel::Permanent); // 0xD8E06406 +constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument, + ErrorLevel::Permanent); // 0xD9006407 + +class ServiceManager { +public: + ResultVal> RegisterService(std::string name, + unsigned int max_sessions); + ResultVal> GetServicePort(const std::string& name); + ResultVal> ConnectToService(const std::string& name); + +private: + /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. + std::unordered_map> registered_services; +}; + +extern std::unique_ptr g_service_manager; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp index d6946c734..34166289c 100644 --- a/src/core/hle/service/sm/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -9,6 +9,7 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/srv.h" namespace Service { @@ -78,25 +79,41 @@ static void GetServiceHandle(Interface* self) { ResultCode res = RESULT_SUCCESS; u32* cmd_buff = Kernel::GetCommandBuffer(); - std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); - auto it = Service::g_srv_services.find(port_name); + size_t name_len = cmd_buff[3]; + if (name_len > Service::kMaxPortSize) { + cmd_buff[1] = ERR_INVALID_NAME_SIZE.raw; + LOG_ERROR(Service_SRV, "called name_len=0x%X, failed with code=0x%08X", name_len, + cmd_buff[1]); + return; + } + std::string name(reinterpret_cast(&cmd_buff[1]), name_len); + bool return_port_on_failure = (cmd_buff[4] & 1) == 0; - if (it != Service::g_srv_services.end()) { - auto client_port = it->second; + // TODO(yuriks): Permission checks go here - auto client_session = client_port->Connect(); - res = client_session.Code(); + auto client_port = g_service_manager->GetServicePort(name); + if (client_port.Failed()) { + cmd_buff[1] = client_port.Code().raw; + LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), + cmd_buff[1]); + return; + } - if (client_session.Succeeded()) { - // Return the client session - cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); - } - LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); + auto session = client_port.Unwrap()->Connect(); + cmd_buff[1] = session.Code().raw; + if (session.Succeeded()) { + cmd_buff[3] = Kernel::g_handle_table.Create(session.MoveFrom()).MoveFrom(); + LOG_DEBUG(Service_SRV, "called service=%s, session handle=0x%08X", name.c_str(), + cmd_buff[3]); + } else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED && return_port_on_failure) { + cmd_buff[1] = ERR_MAX_CONNECTIONS_REACHED.raw; + cmd_buff[3] = Kernel::g_handle_table.Create(client_port.MoveFrom()).MoveFrom(); + LOG_WARNING(Service_SRV, "called service=%s, *port* handle=0x%08X", name.c_str(), + cmd_buff[3]); } else { - LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); - res = UnimplementedFunction(ErrorModule::SRV); + LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), + cmd_buff[1]); } - cmd_buff[1] = res.raw; } /** -- cgit v1.2.3