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::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 handlers; + boost::container::flat_map 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 + 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