From 0b33e36292ca44151da32c7866e4c4394add564b Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Sun, 24 Sep 2017 00:12:58 -0500
Subject: [PATCH] HLE/SRV: Implemented RegisterService.

Now system modules can do more than just crash immediately on startup.
---
 src/core/hle/service/sm/sm.cpp  |  4 ++++
 src/core/hle/service/sm/sm.h    |  3 +++
 src/core/hle/service/sm/srv.cpp | 26 +++++++++++++++++++++++++-
 src/core/hle/service/sm/srv.h   |  1 +
 4 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 5e7fc68f9..854ab9a05 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -36,6 +36,10 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
     std::string name, unsigned int max_sessions) {
 
     CASCADE_CODE(ValidateServiceName(name));
+
+    if (registered_services.find(name) != registered_services.end())
+        return ERR_ALREADY_REGISTERED;
+
     Kernel::SharedPtr<Kernel::ServerPort> server_port;
     Kernel::SharedPtr<Kernel::ClientPort> client_port;
     std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name);
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 8f0dbf2db..9f60a7965 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -32,6 +32,9 @@ constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::Invali
                                        ErrorLevel::Permanent); // 0xD8E06406
 constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument,
                                            ErrorLevel::Permanent); // 0xD9006407
+constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorDescription::AlreadyExists, ErrorModule::OS,
+                                            ErrorSummary::WrongArgument,
+                                            ErrorLevel::Permanent); // 0xD9001BFC
 
 class ServiceManager {
 public:
diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp
index 352941e69..5c955cf54 100644
--- a/src/core/hle/service/sm/srv.cpp
+++ b/src/core/hle/service/sm/srv.cpp
@@ -13,6 +13,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/semaphore.h"
+#include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hle/service/sm/srv.h"
@@ -184,12 +185,35 @@ void SRV::PublishToSubscriber(Kernel::HLERequestContext& ctx) {
                 flags);
 }
 
+void SRV::RegisterService(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp(ctx, 0x3, 4, 0);
+
+    auto name_buf = rp.PopRaw<std::array<char, 8>>();
+    size_t name_len = rp.Pop<u32>();
+    u32 max_sessions = rp.Pop<u32>();
+
+    std::string name(name_buf.data(), std::min(name_len, name_buf.size()));
+
+    auto port = service_manager->RegisterService(name, max_sessions);
+
+    if (port.Failed()) {
+        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+        rb.Push(port.Code());
+        LOG_ERROR(Service_SRV, "called service=%s -> error 0x%08X", name.c_str(), port.Code().raw);
+        return;
+    }
+
+    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
+    rb.Push(RESULT_SUCCESS);
+    rb.PushObjects(port.Unwrap());
+}
+
 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"},
+        {0x00030100, &SRV::RegisterService, "RegisterService"},
         {0x000400C0, nullptr, "UnregisterService"},
         {0x00050100, &SRV::GetServiceHandle, "GetServiceHandle"},
         {0x000600C2, nullptr, "RegisterPort"},
diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h
index 75cca5184..aad839563 100644
--- a/src/core/hle/service/sm/srv.h
+++ b/src/core/hle/service/sm/srv.h
@@ -28,6 +28,7 @@ private:
     void Subscribe(Kernel::HLERequestContext& ctx);
     void Unsubscribe(Kernel::HLERequestContext& ctx);
     void PublishToSubscriber(Kernel::HLERequestContext& ctx);
+    void RegisterService(Kernel::HLERequestContext& ctx);
 
     std::shared_ptr<ServiceManager> service_manager;
     Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore;