diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 46 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 98 | ||||
| -rw-r--r-- | src/core/hle/service/service.h | 150 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.h | 10 | ||||
| -rw-r--r-- | src/core/hle/service/sm/srv.cpp | 71 | ||||
| -rw-r--r-- | src/core/hle/service/sm/srv.h | 26 | 
9 files changed, 355 insertions, 64 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6e602b0c5..b16a89990 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -385,4 +385,4 @@ set(HEADERS  create_directory_groups(${SRCS} ${HEADERS})  add_library(core STATIC ${SRCS} ${HEADERS})  target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) -target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic) +target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt) diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 0922b3f47..a60b8ef00 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -21,4 +21,6 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s      boost::range::remove_erase(connected_sessions, server_session);  } +HLERequestContext::~HLERequestContext() = default; +  } // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 14f682f44..c30184eab 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -7,10 +7,13 @@  #include <memory>  #include <vector>  #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_session.h" -namespace Kernel { +namespace Service { +class ServiceFrameworkBase; +} -class ServerSession; +namespace Kernel {  /**   * Interface implemented by HLE Session handlers. @@ -19,6 +22,8 @@ class ServerSession;   */  class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {  public: +    virtual ~SessionRequestHandler() = default; +      /**       * Handles a sync request from the emulated application.       * @param server_session The ServerSession that was triggered for this sync request, @@ -27,27 +32,56 @@ public:       * this request (ServerSession, Originator thread, Translated command buffer, etc).       * @returns ResultCode the result code of the translate operation.       */ -    virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0; +    virtual void HandleSyncRequest(SharedPtr<ServerSession> server_session) = 0;      /**       * Signals that a client has just connected to this HLE handler and keeps the       * associated ServerSession alive for the duration of the connection.       * @param server_session Owning pointer to the ServerSession associated with the connection.       */ -    void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); +    void ClientConnected(SharedPtr<ServerSession> server_session);      /**       * Signals that a client has just disconnected from this HLE handler and releases the       * associated ServerSession.       * @param server_session ServerSession associated with the connection.       */ -    void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); +    void ClientDisconnected(SharedPtr<ServerSession> server_session);  protected:      /// List of sessions that are connected to this handler.      /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list      // for the duration of the connection. -    std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions; +    std::vector<SharedPtr<ServerSession>> connected_sessions; +}; + +/** + * Class containing information about an in-flight IPC request being handled by an HLE service + * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and + * when possible use the APIs in this class to service the request. + */ +class HLERequestContext { +public: +    ~HLERequestContext(); + +    /// Returns a pointer to the IPC command buffer for this request. +    u32* CommandBuffer() const { +        return cmd_buf; +    } + +    /** +     * Returns the session through which this request was made. This can be used as a map key to +     * access per-client data on services. +     */ +    SharedPtr<ServerSession> Session() const { +        return session; +    } + +private: +    friend class Service::ServiceFrameworkBase; + +    u32* cmd_buf = nullptr; +    SharedPtr<ServerSession> session;  };  } // namespace Kernel diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 0d443aa44..d34968428 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -2,6 +2,7 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <fmt/format.h>  #include "common/logging/log.h"  #include "common/string_util.h"  #include "core/hle/kernel/client_port.h" @@ -45,9 +46,14 @@  #include "core/hle/service/ssl_c.h"  #include "core/hle/service/y2r_u.h" +using Kernel::ClientPort; +using Kernel::ServerPort; +using Kernel::ServerSession; +using Kernel::SharedPtr; +  namespace Service { -std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; +std::unordered_map<std::string, SharedPtr<ClientPort>> g_kernel_named_ports;  /**   * Creates a function string for logging, complete with the name (or header code, depending @@ -69,7 +75,7 @@ static std::string MakeFunctionString(const char* name, const char* port_name,  Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {}  Interface::~Interface() = default; -void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { +void Interface::HandleSyncRequest(SharedPtr<ServerSession> server_session) {      // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which      // session triggered each command. @@ -103,16 +109,91 @@ void Interface::Register(const FunctionInfo* functions, size_t n) {  }  //////////////////////////////////////////////////////////////////////////////////////////////////// + +ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions, +                                           InvokerFn* handler_invoker) +    : service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {} + +ServiceFrameworkBase::~ServiceFrameworkBase() = default; + +void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { +    ASSERT(port == nullptr); +    port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); +    port->SetHleHandler(shared_from_this()); +} + +void ServiceFrameworkBase::InstallAsNamedPort() { +    ASSERT(port == nullptr); +    SharedPtr<ServerPort> server_port; +    SharedPtr<ClientPort> client_port; +    std::tie(server_port, client_port) = ServerPort::CreatePortPair(max_sessions, service_name); +    server_port->SetHleHandler(shared_from_this()); +    AddNamedPort(service_name, std::move(client_port)); +} + +void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, size_t n) { +    handlers.reserve(handlers.size() + n); +    for (size_t i = 0; i < n; ++i) { +        // Usually this array is sorted by id already, so hint to insert at the end +        handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]); +    } +} + +void ServiceFrameworkBase::ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info) { +    IPC::Header header{cmd_buf[0]}; +    int num_params = header.normal_params_size + header.translate_params_size; +    std::string function_name = info == nullptr ? fmt::format("{:#08x}", cmd_buf[0]) : info->name; + +    fmt::MemoryWriter w; +    w.write("function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name, +            cmd_buf[0]); +    for (int i = 1; i <= num_params; ++i) { +        w.write(", [{}]={:#x}", i, cmd_buf[i]); +    } +    w << '}'; + +    LOG_ERROR(Service, "unknown / unimplemented %s", w.c_str()); +    // TODO(bunnei): Hack - ignore error +    cmd_buf[1] = 0; +} + +void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_session) { +    u32* cmd_buf = Kernel::GetCommandBuffer(); + +    // TODO(yuriks): The kernel should be the one handling this as part of translation after +    // everything else is migrated +    Kernel::HLERequestContext context; +    context.cmd_buf = cmd_buf; +    context.session = std::move(server_session); + +    u32 header_code = cmd_buf[0]; +    auto itr = handlers.find(header_code); +    const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second; +    if (info == nullptr || info->handler_callback == nullptr) { +        return ReportUnimplementedFunction(cmd_buf, info); +    } + +    LOG_TRACE(Service, "%s", +              MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf).c_str()); +    handler_invoker(this, info->handler_callback, context); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////  // Module interface +// TODO(yuriks): Move to kernel +void AddNamedPort(std::string name, SharedPtr<ClientPort> port) { +    g_kernel_named_ports.emplace(std::move(name), std::move(port)); +} +  static void AddNamedPort(Interface* interface_) { -    Kernel::SharedPtr<Kernel::ServerPort> server_port; -    Kernel::SharedPtr<Kernel::ClientPort> client_port; +    SharedPtr<ServerPort> server_port; +    SharedPtr<ClientPort> client_port;      std::tie(server_port, client_port) = -        Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); +        ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName());      server_port->SetHleHandler(std::shared_ptr<Interface>(interface_)); -    g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); +    AddNamedPort(interface_->GetPortName(), std::move(client_port));  }  void AddService(Interface* interface_) { @@ -125,8 +206,9 @@ void AddService(Interface* interface_) {  /// Initialize ServiceManager  void Init() { -    SM::g_service_manager = std::make_unique<SM::ServiceManager>(); -    AddNamedPort(new SM::SRV); +    SM::g_service_manager = std::make_shared<SM::ServiceManager>(); +    SM::ServiceManager::InstallInterfaces(SM::g_service_manager); +      AddNamedPort(new ERR::ERR_F);      FS::ArchiveInit(); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 8933d57cc..281ff99bb 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -18,11 +18,16 @@  namespace Kernel {  class ClientPort; +class ServerPort;  class ServerSession;  }  namespace Service { +namespace SM { +class ServiceManager; +} +  static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)  /// Arbitrary default number of maximum connections to an HLE service.  static const u32 DefaultMaxSessions = 10; @@ -30,6 +35,9 @@ static const u32 DefaultMaxSessions = 10;  /**   * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a   * table mapping header ids to handler functions. + * + * @deprecated Use ServiceFramework for new services instead. It allows services to be stateful and + *     is more extensible going forward.   */  class Interface : public Kernel::SessionRequestHandler {  public: @@ -101,6 +109,146 @@ private:      boost::container::flat_map<u32, FunctionInfo> m_functions;  }; +/** + * This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it + * is not meant to be used directly. + * + * @see ServiceFramework + */ +class ServiceFrameworkBase : public Kernel::SessionRequestHandler { +public: +    /// Returns the string identifier used to connect to the service. +    std::string GetServiceName() const { +        return service_name; +    } + +    /** +     * Returns the maximum number of sessions that can be connected to this service at the same +     * time. +     */ +    u32 GetMaxSessions() const { +        return max_sessions; +    } + +    /// Creates a port pair and registers this service with the given ServiceManager. +    void InstallAsService(SM::ServiceManager& service_manager); +    /// Creates a port pair and registers it on the kernel's global port registry. +    void InstallAsNamedPort(); + +    void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; + +protected: +    /// Member-function pointer type of SyncRequest handlers. +    template <typename Self> +    using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); + +private: +    template <typename T> +    friend class ServiceFramework; + +    struct FunctionInfoBase { +        u32 expected_header; +        HandlerFnP<ServiceFrameworkBase> handler_callback; +        const char* name; +    }; + +    using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, +                           Kernel::HLERequestContext& ctx); + +    ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); +    ~ServiceFrameworkBase(); + +    void RegisterHandlersBase(const FunctionInfoBase* functions, size_t n); +    void ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info); + +    /// Identifier string used to connect to the service. +    std::string service_name; +    /// Maximum number of concurrent sessions that this service can handle. +    u32 max_sessions; + +    /** +     * Port where incoming connections will be received. Only created when InstallAsService() or +     * InstallAsNamedPort() are called. +     */ +    Kernel::SharedPtr<Kernel::ServerPort> port; + +    /// Function used to safely up-cast pointers to the derived class before invoking a handler. +    InvokerFn* handler_invoker; +    boost::container::flat_map<u32, FunctionInfoBase> handlers; +}; + +/** + * Framework for implementing HLE services. Dispatches on the header id of incoming SyncRequests + * based on a table mapping header ids to handler functions. Service implementations should inherit + * from ServiceFramework using the CRTP (`class Foo : public ServiceFramework<Foo> { ... };`) and + * populate it with handlers by calling #RegisterHandlers. + * + * In order to avoid duplicating code in the binary and exposing too many implementation details in + * the header, this class is split into a non-templated base (ServiceFrameworkBase) and a template + * deriving from it (ServiceFramework). The functions in this class will mostly only erase the type + * of the passed in function pointers and then delegate the actual work to the implementation in the + * base class. + */ +template <typename Self> +class ServiceFramework : public ServiceFrameworkBase { +protected: +    /// Contains information about a request type which is handled by the service. +    struct FunctionInfo : FunctionInfoBase { +        // TODO(yuriks): This function could be constexpr, but clang is the only compiler that +        // doesn't emit an ICE or a wrong diagnostic because of the static_cast. + +        /** +         * Constructs a FunctionInfo for a function. +         * +         * @param expected_header request header in the command buffer which will trigger dispatch +         *     to this handler +         * @param handler_callback member function in this service which will be called to handle +         *     the request +         * @param name human-friendly name for the request. Used mostly for logging purposes. +         */ +        FunctionInfo(u32 expected_header, HandlerFnP<Self> handler_callback, const char* name) +            : FunctionInfoBase{ +                  expected_header, +                  // Type-erase member function pointer by casting it down to the base class. +                  static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {} +    }; + +    /** +     * Initializes the handler with no functions installed. +     * @param max_sessions Maximum number of sessions that can be +     * connected to this service at the same time. +     */ +    ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions) +        : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} + +    /// Registers handlers in the service. +    template <size_t N> +    void RegisterHandlers(const FunctionInfo (&functions)[N]) { +        RegisterHandlers(functions, N); +    } + +    /** +     * Registers handlers in the service. Usually prefer using the other RegisterHandlers +     * overload in order to avoid needing to specify the array size. +     */ +    void RegisterHandlers(const FunctionInfo* functions, size_t n) { +        RegisterHandlersBase(functions, n); +    } + +private: +    /** +     * This function is used to allow invocation of pointers to handlers stored in the base class +     * without needing to expose the type of this derived class. Pointers-to-member may require a +     * fixup when being up or downcast, and thus code that does that needs to know the concrete type +     * of the derived class in order to invoke one of it's functions through a pointer. +     */ +    static void Invoker(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, +                        Kernel::HLERequestContext& ctx) { +        // Cast back up to our original types and call the member function +        (static_cast<Self*>(object)->*static_cast<HandlerFnP<Self>>(member))(ctx); +    } +}; +  /// Initialize ServiceManager  void Init(); @@ -110,6 +258,8 @@ 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; +/// Adds a port to the named port table +void AddNamedPort(std::string name, Kernel::SharedPtr<Kernel::ClientPort> port);  /// 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 index 361f7a0a9..5e7fc68f9 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -3,11 +3,13 @@  // Refer to the license.txt file included.  #include <tuple> +#include "common/assert.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/result.h"  #include "core/hle/service/sm/sm.h" +#include "core/hle/service/sm/srv.h"  namespace Service {  namespace SM { @@ -22,6 +24,14 @@ static ResultCode ValidateServiceName(const std::string& name) {      return RESULT_SUCCESS;  } +void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self) { +    ASSERT(self->srv_interface.expired()); + +    auto srv = std::make_shared<SRV>(self); +    srv->InstallAsNamedPort(); +    self->srv_interface = srv; +} +  ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService(      std::string name, unsigned int max_sessions) { @@ -30,7 +40,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService      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)); +    registered_services.emplace(std::move(name), std::move(client_port));      return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));  } @@ -53,7 +63,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToSer      return client_port->Connect();  } -std::unique_ptr<ServiceManager> g_service_manager; +std::shared_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 index 5fac5455c..8f0dbf2db 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -20,6 +20,8 @@ class SessionRequestHandler;  namespace Service {  namespace SM { +class SRV; +  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, @@ -33,17 +35,21 @@ constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::Wr  class ServiceManager {  public: +    static void InstallInterfaces(std::shared_ptr<ServiceManager> self); +      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::weak_ptr<SRV> srv_interface; + +    /// Map of registered services, retrieved using GetServicePort or ConnectToService.      std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services;  }; -extern std::unique_ptr<ServiceManager> g_service_manager; +extern std::shared_ptr<ServiceManager> 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 063b1b0fc..b8b62b068 100644 --- a/src/core/hle/service/sm/srv.cpp +++ b/src/core/hle/service/sm/srv.cpp @@ -20,8 +20,6 @@ namespace SM {  constexpr int MAX_PENDING_NOTIFICATIONS = 16; -static Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore; -  /**   * SRV::RegisterClient service function   *  Inputs: @@ -31,8 +29,8 @@ static Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore;   *      0: 0x00010040   *      1: ResultCode   */ -static void RegisterClient(Interface* self) { -    u32* cmd_buff = Kernel::GetCommandBuffer(); +void SRV::RegisterClient(Kernel::HLERequestContext& ctx) { +    u32* cmd_buff = ctx.CommandBuffer();      if (cmd_buff[1] != IPC::CallingPidDesc()) {          cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); // 0x40 @@ -54,8 +52,8 @@ static void RegisterClient(Interface* self) {   *      2: Translation descriptor: 0x20   *      3: Handle to semaphore signaled on process notification   */ -static void EnableNotification(Interface* self) { -    u32* cmd_buff = Kernel::GetCommandBuffer(); +void SRV::EnableNotification(Kernel::HLERequestContext& ctx) { +    u32* cmd_buff = ctx.CommandBuffer();      notification_semaphore =          Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap(); @@ -78,9 +76,9 @@ static void EnableNotification(Interface* self) {   *      1: ResultCode   *      3: Service handle   */ -static void GetServiceHandle(Interface* self) { +void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) {      ResultCode res = RESULT_SUCCESS; -    u32* cmd_buff = Kernel::GetCommandBuffer(); +    u32* cmd_buff = ctx.CommandBuffer();      size_t name_len = cmd_buff[3];      if (name_len > Service::kMaxPortSize) { @@ -94,7 +92,7 @@ static void GetServiceHandle(Interface* self) {      // TODO(yuriks): Permission checks go here -    auto client_port = g_service_manager->GetServicePort(name); +    auto client_port = 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(), @@ -128,8 +126,8 @@ static void GetServiceHandle(Interface* self) {   *      0: 0x00090040   *      1: ResultCode   */ -static void Subscribe(Interface* self) { -    u32* cmd_buff = Kernel::GetCommandBuffer(); +void SRV::Subscribe(Kernel::HLERequestContext& ctx) { +    u32* cmd_buff = ctx.CommandBuffer();      u32 notification_id = cmd_buff[1]; @@ -147,8 +145,8 @@ static void Subscribe(Interface* self) {   *      0: 0x000A0040   *      1: ResultCode   */ -static void Unsubscribe(Interface* self) { -    u32* cmd_buff = Kernel::GetCommandBuffer(); +void SRV::Unsubscribe(Kernel::HLERequestContext& ctx) { +    u32* cmd_buff = ctx.CommandBuffer();      u32 notification_id = cmd_buff[1]; @@ -167,8 +165,8 @@ static void Unsubscribe(Interface* self) {   *      0: 0x000C0040   *      1: ResultCode   */ -static void PublishToSubscriber(Interface* self) { -    u32* cmd_buff = Kernel::GetCommandBuffer(); +void SRV::PublishToSubscriber(Kernel::HLERequestContext& ctx) { +    u32* cmd_buff = ctx.CommandBuffer();      u32 notification_id = cmd_buff[1];      u8 flags = cmd_buff[2] & 0xFF; @@ -179,31 +177,28 @@ static void PublishToSubscriber(Interface* self) {                  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); -    notification_semaphore = nullptr; +SRV::SRV(std::shared_ptr<ServiceManager> service_manager) +    : ServiceFramework("srv:", 4), service_manager(std::move(service_manager)) { +    static const FunctionInfo functions[] = { +        {0x00010002, &SRV::RegisterClient, "RegisterClient"}, +        {0x00020000, &SRV::EnableNotification, "EnableNotification"}, +        {0x00030100, nullptr, "RegisterService"}, +        {0x000400C0, nullptr, "UnregisterService"}, +        {0x00050100, &SRV::GetServiceHandle, "GetServiceHandle"}, +        {0x000600C2, nullptr, "RegisterPort"}, +        {0x000700C0, nullptr, "UnregisterPort"}, +        {0x00080100, nullptr, "GetPort"}, +        {0x00090040, &SRV::Subscribe, "Subscribe"}, +        {0x000A0040, &SRV::Unsubscribe, "Unsubscribe"}, +        {0x000B0000, nullptr, "ReceiveNotification"}, +        {0x000C0080, &SRV::PublishToSubscriber, "PublishToSubscriber"}, +        {0x000D0040, nullptr, "PublishAndGetSubscriber"}, +        {0x000E00C0, nullptr, "IsServiceRegistered"}, +    }; +    RegisterHandlers(functions);  } -SRV::~SRV() { -    notification_semaphore = nullptr; -} +SRV::~SRV() = default;  } // namespace SM  } // namespace Service diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h index 4196ca1e2..75cca5184 100644 --- a/src/core/hle/service/sm/srv.h +++ b/src/core/hle/service/sm/srv.h @@ -4,21 +4,33 @@  #pragma once -#include <string> +#include "core/hle/kernel/kernel.h"  #include "core/hle/service/service.h" +namespace Kernel { +class HLERequestContext; +class Semaphore; +} +  namespace Service {  namespace SM {  /// Interface to "srv:" service -class SRV final : public Interface { +class SRV final : public ServiceFramework<SRV> {  public: -    SRV(); -    ~SRV() override; +    explicit SRV(std::shared_ptr<ServiceManager> service_manager); +    ~SRV(); + +private: +    void RegisterClient(Kernel::HLERequestContext& ctx); +    void EnableNotification(Kernel::HLERequestContext& ctx); +    void GetServiceHandle(Kernel::HLERequestContext& ctx); +    void Subscribe(Kernel::HLERequestContext& ctx); +    void Unsubscribe(Kernel::HLERequestContext& ctx); +    void PublishToSubscriber(Kernel::HLERequestContext& ctx); -    std::string GetPortName() const override { -        return "srv:"; -    } +    std::shared_ptr<ServiceManager> service_manager; +    Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore;  };  } // namespace SM  | 
