diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 19 | ||||
| -rw-r--r-- | src/core/hle/service/service.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 58 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.h | 49 | ||||
| -rw-r--r-- | src/core/hle/service/sm/srv.cpp (renamed from src/core/hle/service/srv.cpp) | 68 | ||||
| -rw-r--r-- | src/core/hle/service/sm/srv.h (renamed from src/core/hle/service/srv.h) | 5 | 
7 files changed, 166 insertions, 41 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 51ee80bc4..6e602b0c5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -156,8 +156,9 @@ 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/srv.cpp              hle/service/ssl_c.cpp              hle/service/y2r_u.cpp              hle/shared_page.cpp @@ -352,8 +353,9 @@ 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/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..1b64ee77d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -38,15 +38,15 @@  #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/srv.h"  #include "core/hle/service/ssl_c.h"  #include "core/hle/service/y2r_u.h"  namespace Service {  std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; -std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;  /**   * Creates a function string for logging, complete with the name (or header code, depending @@ -115,18 +115,17 @@ static void AddNamedPort(Interface* interface_) {  }  void AddService(Interface* interface_) { -    Kernel::SharedPtr<Kernel::ServerPort> server_port; -    Kernel::SharedPtr<Kernel::ClientPort> 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>(interface_)); -    g_srv_services.emplace(interface_->GetPortName(), std::move(client_port));  }  /// Initialize ServiceManager  void Init() { -    AddNamedPort(new SRV::SRV); +    SM::g_service_manager = std::make_unique<SM::ServiceManager>(); +    AddNamedPort(new SM::SRV);      AddNamedPort(new ERR::ERR_F);      FS::ArchiveInit(); @@ -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<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; -/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> 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 <tuple> +#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<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService( +    std::string name, unsigned int max_sessions) { + +    CASCADE_CODE(ValidateServiceName(name)); +    Kernel::SharedPtr<Kernel::ServerPort> server_port; +    Kernel::SharedPtr<Kernel::ClientPort> client_port; +    std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); + +    registered_services.emplace(name, std::move(client_port)); +    return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); +} + +ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> 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<Kernel::SharedPtr<Kernel::ClientPort>>(it->second); +} + +ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService( +    const std::string& name) { + +    CASCADE_RESULT(auto client_port, GetServicePort(name)); +    return client_port->Connect(); +} + +std::unique_ptr<ServiceManager> 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 <string> +#include <unordered_map> +#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<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, +                                                                     unsigned int max_sessions); +    ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); +    ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); + +private: +    /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. +    std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services; +}; + +extern std::unique_ptr<ServiceManager> g_service_manager; + +} // namespace SM +} // namespace Service diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/sm/srv.cpp index 130c9d25e..34166289c 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -7,14 +7,17 @@  #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/srv.h" +#include "core/hle/service/sm/sm.h" +#include "core/hle/service/sm/srv.h"  namespace Service { -namespace SRV { +namespace SM { -static Kernel::SharedPtr<Kernel::Event> event_handle; +constexpr int MAX_PENDING_NOTIFICATIONS = 16; + +static Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore;  /**   * SRV::RegisterClient service function @@ -51,14 +54,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");  } @@ -77,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<const char*>(&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;  }  /** @@ -177,12 +195,12 @@ const Interface::FunctionInfo FunctionTable[] = {  SRV::SRV() {      Register(FunctionTable); -    event_handle = nullptr; +    notification_semaphore = nullptr;  }  SRV::~SRV() { -    event_handle = nullptr; +    notification_semaphore = nullptr;  } -} // namespace SRV +} // namespace SM  } // namespace Service diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/sm/srv.h index d3a9de879..4196ca1e2 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/sm/srv.h @@ -4,10 +4,11 @@  #pragma once +#include <string>  #include "core/hle/service/service.h"  namespace Service { -namespace SRV { +namespace SM {  /// Interface to "srv:" service  class SRV final : public Interface { @@ -20,5 +21,5 @@ public:      }  }; -} // namespace SRV +} // namespace SM  } // namespace Service  | 
