From 21671d05a362f98cd24dcc520a3da163e349fe07 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Mon, 10 May 2021 16:08:06 -0700
Subject: [PATCH] hle: service: Add support for dispatching TIPC requests.

---
 src/core/hle/service/service.cpp | 29 +++++++++++++++++++++++++++++
 src/core/hle/service/service.h   | 24 +++++++++++++++++++++++-
 2 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index e36c35a861..2c9b2ce6db 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -133,6 +133,16 @@ void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* function
     }
 }
 
+void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions,
+                                                    std::size_t n) {
+    handlers_tipc.reserve(handlers_tipc.size() + n);
+    for (std::size_t i = 0; i < n; ++i) {
+        // Usually this array is sorted by id already, so hint to insert at the end
+        handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header,
+                                   functions[i]);
+    }
+}
+
 void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx,
                                                        const FunctionInfoBase* info) {
     auto cmd_buf = ctx.CommandBuffer();
@@ -167,6 +177,20 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
     handler_invoker(this, info->handler_callback, ctx);
 }
 
+void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) {
+    boost::container::flat_map<u32, FunctionInfoBase>::iterator itr;
+
+    itr = handlers_tipc.find(ctx.GetCommand());
+
+    const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second;
+    if (info == nullptr || info->handler_callback == nullptr) {
+        return ReportUnimplementedFunction(ctx, info);
+    }
+
+    LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
+    handler_invoker(this, info->handler_callback, ctx);
+}
+
 ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
                                                    Kernel::HLERequestContext& ctx) {
     const auto guard = LockService();
@@ -190,6 +214,11 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& sessi
         break;
     }
     default:
+        if (ctx.IsTipc()) {
+            InvokeRequestTipc(ctx);
+            break;
+        }
+
         UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType());
     }
 
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 51e22a7913..3dfb0740a3 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -21,7 +21,9 @@ class System;
 
 namespace Kernel {
 class HLERequestContext;
-}
+class KClientPort;
+class KServerSession;
+} // namespace Kernel
 
 namespace Service {
 
@@ -67,6 +69,10 @@ public:
 
     /// Invokes a service request routine using the HIPC protocol.
     void InvokeRequest(Kernel::HLERequestContext& ctx);
+
+    /// Invokes a service request routine using the HIPC protocol.
+    void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
+
     /// Creates a port pair and registers it on the kernel's global port registry.
     Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel);
 
@@ -105,6 +111,7 @@ private:
     ~ServiceFrameworkBase() override;
 
     void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
+    void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
     void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
 
     /// Identifier string used to connect to the service.
@@ -119,6 +126,7 @@ private:
     /// 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;
+    boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
 
     /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
     Common::SpinLock lock_service;
@@ -186,6 +194,20 @@ protected:
         RegisterHandlersBase(functions, n);
     }
 
+    /// Registers handlers in the service.
+    template <std::size_t N>
+    void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
+        RegisterHandlersTipc(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 RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) {
+        RegisterHandlersBaseTipc(functions, n);
+    }
+
 private:
     /**
      * This function is used to allow invocation of pointers to handlers stored in the base class