From 073653e858abf377fd1ebbdb071809c8830ce99d Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 14 Jun 2016 18:03:30 -0500 Subject: [PATCH 01/18] Kernel/IPC: Use Ports and Sessions as the fundamental building block of Inter Process Communication. All handles obtained via srv::GetServiceHandle or svcConnectToPort are references to ClientSessions. Service modules will wait on the counterpart of those ClientSessions (Called ServerSessions) using svcReplyAndReceive or svcWaitSynchronization[1|N], and will be awoken when a SyncRequest is performed. HLE Interfaces are now ClientPorts which override the HandleSyncRequest virtual member function to perform command handling immediately. --- src/core/CMakeLists.txt | 6 +- src/core/hle/kernel/client_port.cpp | 7 ++ src/core/hle/kernel/client_port.h | 23 ++++-- src/core/hle/kernel/client_session.cpp | 42 ++++++++++ src/core/hle/kernel/client_session.h | 50 ++++++++++++ src/core/hle/kernel/kernel.h | 34 ++++---- src/core/hle/kernel/server_session.cpp | 58 ++++++++++++++ .../kernel/{session.h => server_session.h} | 77 ++++++++++--------- src/core/hle/service/fs/archive.cpp | 12 +-- src/core/hle/service/fs/archive.h | 12 +-- src/core/hle/service/fs/fs_user.cpp | 9 ++- src/core/hle/service/service.cpp | 16 ++-- src/core/hle/service/service.h | 21 +++-- src/core/hle/service/soc_u.cpp | 2 +- src/core/hle/service/srv.cpp | 17 +++- src/core/hle/svc.cpp | 18 ++++- 16 files changed, 315 insertions(+), 89 deletions(-) create mode 100644 src/core/hle/kernel/client_session.cpp create mode 100644 src/core/hle/kernel/client_session.h create mode 100644 src/core/hle/kernel/server_session.cpp rename src/core/hle/kernel/{session.h => server_session.h} (75%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 299f1f261..59260d2e8 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -36,6 +36,7 @@ set(SRCS hle/applets/swkbd.cpp hle/kernel/address_arbiter.cpp hle/kernel/client_port.cpp + hle/kernel/client_session.cpp hle/kernel/event.cpp hle/kernel/kernel.cpp hle/kernel/memory.cpp @@ -44,7 +45,7 @@ set(SRCS hle/kernel/resource_limit.cpp hle/kernel/semaphore.cpp hle/kernel/server_port.cpp - hle/kernel/session.cpp + hle/kernel/server_session.cpp hle/kernel/shared_memory.cpp hle/kernel/thread.cpp hle/kernel/timer.cpp @@ -184,6 +185,7 @@ set(HEADERS hle/applets/swkbd.h hle/kernel/address_arbiter.h hle/kernel/client_port.h + hle/kernel/client_session.h hle/kernel/event.h hle/kernel/kernel.h hle/kernel/memory.h @@ -192,7 +194,7 @@ set(HEADERS hle/kernel/resource_limit.h hle/kernel/semaphore.h hle/kernel/server_port.h - hle/kernel/session.h + hle/kernel/server_session.h hle/kernel/shared_memory.h hle/kernel/thread.h hle/kernel/timer.h diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index aedc6f989..5ee7679eb 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -6,10 +6,17 @@ #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} +void ClientPort::AddWaitingSession(SharedPtr server_session) { + server_port->pending_sessions.push_back(server_session); + // Wake the threads waiting on the ServerPort + server_port->WakeupAllWaitingThreads(); +} + } // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index d28147718..eb0882870 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -11,16 +11,27 @@ namespace Kernel { class ServerPort; +class ServerSession; class ClientPort : public Object { public: friend class ServerPort; - std::string GetTypeName() const override { - return "ClientPort"; - } - std::string GetName() const override { - return name; - } + + /** + * Adds the specified server session to the queue of pending sessions of the associated ServerPort + * @param server_session Server session to add to the queue + */ + virtual void AddWaitingSession(SharedPtr server_session); + + /** + * Handle a sync request from the emulated application. + * Only HLE services should override this function. + * @returns ResultCode from the operation. + */ + virtual ResultCode HandleSyncRequest() { return RESULT_SUCCESS; } + + std::string GetTypeName() const override { return "ClientPort"; } + std::string GetName() const override { return name; } static const HandleType HANDLE_TYPE = HandleType::ClientPort; HandleType GetHandleType() const override { diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp new file mode 100644 index 000000000..f1ad9b65b --- /dev/null +++ b/src/core/hle/kernel/client_session.cpp @@ -0,0 +1,42 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +ClientSession::ClientSession() {} +ClientSession::~ClientSession() {} + +ResultVal> ClientSession::Create(SharedPtr server_session, SharedPtr client_port, std::string name) { + SharedPtr client_session(new ClientSession); + + client_session->name = std::move(name); + client_session->server_session = server_session; + client_session->client_port = client_port; + + return MakeResult>(std::move(client_session)); +} + +ResultCode ClientSession::HandleSyncRequest() { + // Signal the server session that new data is available + ResultCode result = server_session->HandleSyncRequest(); + + if (result.IsError()) + return result; + + // Tell the client port to handle the request in case it's an HLE service. + // The client port can be nullptr for port-less sessions (Like for example File and Directory sessions). + if (client_port != nullptr) + result = client_port->HandleSyncRequest(); + + return result; +} + +} // namespace diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h new file mode 100644 index 000000000..4fe9b4517 --- /dev/null +++ b/src/core/hle/kernel/client_session.h @@ -0,0 +1,50 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ClientPort; +class ServerSession; + +class ClientSession final : public Object { +public: + /** + * Creates a client session. + * @param server_session The server session associated with this client session + * @param client_port The client port which this session is connected to + * @param name Optional name of client session + * @return The created client session + */ + static ResultVal> Create(SharedPtr server_session, SharedPtr client_port, std::string name = "Unknown"); + + std::string GetTypeName() const override { return "ClientSession"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ClientSession; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + /** + * Handle a SyncRequest from the emulated application. + * @return ResultCode of the operation. + */ + ResultCode HandleSyncRequest(); + + std::string name; ///< Name of client port (optional) + SharedPtr server_session; ///< The server session associated with this client session. + SharedPtr client_port; ///< The client port which this session is connected to. + +private: + ClientSession(); + ~ClientSession() override; +}; + +} // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 231cf7b75..c11c14b7d 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -31,22 +31,24 @@ enum KernelHandle : Handle { }; enum class HandleType : u32 { - Unknown = 0, + Unknown = 0, - Session = 2, - Event = 3, - Mutex = 4, - SharedMemory = 5, - Redirection = 6, - Thread = 7, - Process = 8, - AddressArbiter = 9, - Semaphore = 10, - Timer = 11, - ResourceLimit = 12, - CodeSet = 13, - ClientPort = 14, - ServerPort = 15, + + Event = 3, + Mutex = 4, + SharedMemory = 5, + Redirection = 6, + Thread = 7, + Process = 8, + AddressArbiter = 9, + Semaphore = 10, + Timer = 11, + ResourceLimit = 12, + CodeSet = 13, + ClientPort = 14, + ServerPort = 15, + ClientSession = 16, + ServerSession = 17, }; enum { @@ -82,7 +84,7 @@ public: */ bool IsWaitable() const { switch (GetHandleType()) { - case HandleType::Session: + case HandleType::ServerSession: case HandleType::ServerPort: case HandleType::Event: case HandleType::Mutex: diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp new file mode 100644 index 000000000..9f5350ce5 --- /dev/null +++ b/src/core/hle/kernel/server_session.cpp @@ -0,0 +1,58 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +ServerSession::ServerSession() {} +ServerSession::~ServerSession() {} + +ResultVal> ServerSession::Create(std::string name) { + SharedPtr server_session(new ServerSession); + + server_session->name = std::move(name); + server_session->signaled = false; + + return MakeResult>(std::move(server_session)); +} + +bool ServerSession::ShouldWait() { + return !signaled; +} + +void ServerSession::Acquire() { + ASSERT_MSG(!ShouldWait(), "object unavailable!"); + signaled = false; +} + +ResultCode ServerSession::HandleSyncRequest() { + // The ServerSession received a sync request, this means that there's new data available + // from one of its ClientSessions, so wake up any threads that may be waiting on a svcReplyAndReceive or similar. + signaled = true; + WakeupAllWaitingThreads(); + return RESULT_SUCCESS; +} + +SharedPtr ServerSession::CreateClientSession() { + // In Citra, some types of ServerSessions (File and Directory sessions) are not created as a pair of Server-Client sessions, + // but are instead created as a single ServerSession, which then hands over a ClientSession on demand (When opening the File or Directory). + // The real kernel (Or more specifically, the real FS service) does create the pair of Sessions at the same time (via svcCreateSession), and simply + // stores the ClientSession until it is needed. + return ClientSession::Create(SharedPtr(this), nullptr, name + "Client").MoveFrom(); +} + +std::tuple, SharedPtr> ServerSession::CreateSessionPair(SharedPtr client_port, std::string name) { + auto server_session = ServerSession::Create(name + "Server").MoveFrom(); + auto client_session = ClientSession::Create(server_session, client_port, name + "Client").MoveFrom(); + + return std::make_tuple(server_session, client_session); +} + +} diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/server_session.h similarity index 75% rename from src/core/hle/kernel/session.h rename to src/core/hle/kernel/server_session.h index ec025f732..eab9fe211 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/server_session.h @@ -162,57 +162,64 @@ inline u32* GetCommandBuffer(const int offset = 0) { offset); } +class ClientSession; +class ClientPort; + /** - * Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS + * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS * primitive for communication between different processes, and are used to implement service calls * to the various system services. * * To make a service call, the client must write the command header and parameters to the buffer * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest - * SVC call with its Session handle. The kernel will read the command header, using it to marshall + * SVC call with its ClientSession handle. The kernel will read the command header, using it to marshall * the parameters to the process at the server endpoint of the session. After the server replies to * the request, the response is marshalled back to the caller's TLS buffer and control is * transferred back to it. - * - * In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC - * request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called - * with the session handle, this class's SyncRequest method is called, which should read the TLS - * buffer and emulate the call accordingly. Since the code can directly read the emulated memory, - * no parameter marshalling is done. - * - * In the long term, this should be turned into the full-fledged IPC mechanism implemented by - * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as - * opposed to HLE simulations. */ -class Session : public WaitObject { +class ServerSession : public WaitObject { public: - Session(); - ~Session() override; - - std::string GetTypeName() const override { - return "Session"; - } - - static const HandleType HANDLE_TYPE = HandleType::Session; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } + ServerSession(); + ~ServerSession() override; /** - * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls - * aren't supported yet. + * Creates a server session. + * @param name Optional name of the server session + * @return The created server session */ - virtual ResultVal SyncRequest() = 0; + static ResultVal> Create(std::string name = "Unknown"); - // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object - // passed into WaitSynchronization. Figure out the meaning of them. + std::string GetTypeName() const override { return "ServerSession"; } - bool ShouldWait() override { - return true; - } + static const HandleType HANDLE_TYPE = HandleType::ServerSession; + HandleType GetHandleType() const override { return HANDLE_TYPE; } - void Acquire() override { - ASSERT_MSG(!ShouldWait(), "object unavailable!"); - } + /** + * Creates a pair of ServerSession and an associated ClientSession. + * @param client_port ClientPort to which the sessions are connected + * @param name Optional name of the ports + * @return The created session tuple + */ + static std::tuple, SharedPtr> CreateSessionPair(SharedPtr client_port, std::string name = "Unknown"); + + /** + * Creates a portless ClientSession and associates it with this ServerSession. + * @returns ClientSession The newly created ClientSession. + */ + SharedPtr CreateClientSession(); + + /** + * Handle a sync request from the emulated application. + * Only HLE services should override this function. + * @returns ResultCode from the operation. + */ + virtual ResultCode HandleSyncRequest(); + + bool ShouldWait() override; + + void Acquire() override; + + std::string name; ///< The name of this session (optional) + bool signaled; ///< Whether there's new data available to this ServerSession }; } diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 4c29784e8..da009df91 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -92,7 +92,7 @@ File::File(std::unique_ptr&& backend, const FileSys::Path& File::~File() {} -ResultVal File::SyncRequest() { +ResultCode File::HandleSyncRequest() { u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { @@ -193,10 +193,10 @@ ResultVal File::SyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return error; + return ServerSession::HandleSyncRequest(); } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return MakeResult(false); + return ServerSession::HandleSyncRequest(); } Directory::Directory(std::unique_ptr&& backend, @@ -205,7 +205,7 @@ Directory::Directory(std::unique_ptr&& backend, Directory::~Directory() {} -ResultVal Directory::SyncRequest() { +ResultCode Directory::HandleSyncRequest() { u32* cmd_buff = Kernel::GetCommandBuffer(); DirectoryCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { @@ -236,10 +236,10 @@ ResultVal Directory::SyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return MakeResult(false); + return ServerSession::HandleSyncRequest(); } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return MakeResult(false); + return ServerSession::HandleSyncRequest(); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 21ed9717b..22e659c40 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -8,7 +8,7 @@ #include #include "common/common_types.h" #include "core/file_sys/archive_backend.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" namespace FileSys { @@ -41,7 +41,7 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1 }; typedef u64 ArchiveHandle; -class File : public Kernel::Session { +class File : public Kernel::ServerSession { public: File(std::unique_ptr&& backend, const FileSys::Path& path); ~File(); @@ -49,14 +49,15 @@ public: std::string GetName() const override { return "Path: " + path.DebugStr(); } - ResultVal SyncRequest() override; + + ResultCode HandleSyncRequest() override; FileSys::Path path; ///< Path of the file u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means std::unique_ptr backend; ///< File backend interface }; -class Directory : public Kernel::Session { +class Directory : public Kernel::ServerSession { public: Directory(std::unique_ptr&& backend, const FileSys::Path& path); ~Directory(); @@ -64,7 +65,8 @@ public: std::string GetName() const override { return "Directory: " + path.DebugStr(); } - ResultVal SyncRequest() override; + + ResultCode HandleSyncRequest() override; FileSys::Path path; ///< Path of the directory std::unique_ptr backend; ///< File backend interface diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 9ec17b395..bb78091f9 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -8,6 +8,7 @@ #include "common/logging/log.h" #include "common/scope_exit.h" #include "common/string_util.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" @@ -17,7 +18,7 @@ // Namespace FS_User using Kernel::SharedPtr; -using Kernel::Session; +using Kernel::ServerSession; namespace Service { namespace FS { @@ -70,7 +71,7 @@ static void OpenFile(Service::Interface* self) { ResultVal> file_res = OpenFileFromArchive(archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table.Create((*file_res)->CreateClientSession()).MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -130,7 +131,7 @@ static void OpenFileDirectly(Service::Interface* self) { ResultVal> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table.Create((*file_res)->CreateClientSession()).MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", @@ -391,7 +392,7 @@ static void OpenDirectory(Service::Interface* self) { ResultVal> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); cmd_buff[1] = dir_res.Code().raw; if (dir_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table.Create((*dir_res)->CreateClientSession()).MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index ca7eeac8a..f51a042ff 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -41,8 +41,8 @@ namespace Service { -std::unordered_map> g_kernel_named_ports; -std::unordered_map> g_srv_services; +std::unordered_map> g_kernel_named_ports; +std::unordered_map> g_srv_services; /** * Creates a function string for logging, complete with the name (or header code, depending @@ -61,7 +61,7 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -ResultVal Interface::SyncRequest() { +ResultCode Interface::HandleSyncRequest() { u32* cmd_buff = Kernel::GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -75,14 +75,14 @@ ResultVal Interface::SyncRequest() { // TODO(bunnei): Hack - ignore error cmd_buff[1] = 0; - return MakeResult(false); + return RESULT_SUCCESS; } LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); itr->second.func(this); - return MakeResult(false); // TODO: Implement return from actual function + return RESULT_SUCCESS; // TODO: Implement return from actual function, it should fail if the parameter translation fails } void Interface::Register(const FunctionInfo* functions, size_t n) { @@ -97,10 +97,16 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { + interface_->name = interface_->GetPortName(); + interface_->active_sessions = 0; + interface_->max_sessions = interface_->GetMaxSessions(); g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); } void AddService(Interface* interface_) { + interface_->name = interface_->GetPortName(); + interface_->active_sessions = 0; + interface_->max_sessions = interface_->GetMaxSessions(); g_srv_services.emplace(interface_->GetPortName(), interface_); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 29daacfc4..fd15ad03f 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -9,7 +9,8 @@ #include #include #include "common/common_types.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -18,9 +19,10 @@ namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) +static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE port /// Interface to a CTROS service -class Interface : public Kernel::Session { +class Interface : public Kernel::ClientPort { // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be // just something that encapsulates a session and acts as a helper to implement service // processes. @@ -33,6 +35,15 @@ public: version.raw = raw_version; } + /** + * Gets the maximum allowed number of sessions that can be connected to this port at the same time. + * It should be overwritten by each service implementation for more fine-grained control. + * @returns The maximum number of connections allowed. + */ + virtual u32 GetMaxSessions() { return DefaultMaxSessions; } + + void AddWaitingSession(Kernel::SharedPtr server_session) override { } + typedef void (*Function)(Interface*); struct FunctionInfo { @@ -49,7 +60,7 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultVal SyncRequest() override; + ResultCode HandleSyncRequest() override; protected: /** @@ -81,9 +92,9 @@ void Init(); void Shutdown(); /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. -extern std::unordered_map> g_kernel_named_ports; +extern std::unordered_map> g_kernel_named_ports; /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map> g_srv_services; +extern std::unordered_map> g_srv_services; /// Adds a service to the services table void AddService(Interface* interface_); diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 46b75db25..2e8b2fc00 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/scope_exit.h" -#include "core/hle/kernel/session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" #include "core/hle/service/soc_u.h" #include "core/memory.h" diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index b25be413a..eb2e06041 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -2,8 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/service/srv.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/event.h" #include "core/hle/service/srv.h" @@ -81,7 +85,18 @@ static void GetServiceHandle(Service::Interface* self) { auto it = Service::g_srv_services.find(port_name); if (it != Service::g_srv_services.end()) { - cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom(); + auto client_port = it->second; + + // Create a new session pair + auto sessions = Kernel::ServerSession::CreateSessionPair(client_port, port_name); + auto client_session = std::get>(sessions); + auto server_session = std::get>(sessions); + + // Add the server session to the port's queue + client_port->AddWaitingSession(server_session); + + // 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]); } else { LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index c6b80dc50..be03e53bc 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -13,6 +13,7 @@ #include "core/hle/function_wrappers.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/mutex.h" @@ -222,20 +223,31 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { return ERR_NOT_FOUND; } - CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second)); + auto client_port = it->second; + + // Create a new session pair + auto sessions = Kernel::ServerSession::CreateSessionPair(client_port, port_name); + auto client_session = std::get>(sessions); + auto server_session = std::get>(sessions); + + // Add the server session to the port's queue + client_port->AddWaitingSession(server_session); + + // Return the client session + CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session)); return RESULT_SUCCESS; } /// Synchronize to an OS service static ResultCode SendSyncRequest(Handle handle) { - SharedPtr session = Kernel::g_handle_table.Get(handle); + SharedPtr session = Kernel::g_handle_table.Get(handle); if (session == nullptr) { return ERR_INVALID_HANDLE; } LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); - return session->SyncRequest().Code(); + return session->HandleSyncRequest(); } /// Close a handle From 0a33d915f88b89e2fae20edc1e33a8ef60a2519c Mon Sep 17 00:00:00 2001 From: Subv Date: Fri, 17 Jun 2016 15:24:38 -0500 Subject: [PATCH 02/18] fixup! Kernel/IPC: Use Ports and Sessions as the fundamental building block of Inter Process Communication. --- src/core/hle/kernel/kernel.h | 5 +++-- src/core/hle/kernel/server_session.cpp | 2 +- src/core/hle/kernel/server_session.h | 2 +- src/core/hle/service/service.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c11c14b7d..4bd505b5d 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -84,13 +84,13 @@ public: */ bool IsWaitable() const { switch (GetHandleType()) { - case HandleType::ServerSession: - case HandleType::ServerPort: case HandleType::Event: case HandleType::Mutex: case HandleType::Thread: case HandleType::Semaphore: case HandleType::Timer: + case HandleType::ServerPort: + case HandleType::ServerSession: return true; case HandleType::Unknown: @@ -101,6 +101,7 @@ public: case HandleType::ResourceLimit: case HandleType::CodeSet: case HandleType::ClientPort: + case HandleType::ClientSession: return false; } } diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 9f5350ce5..720c0eb94 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -48,7 +48,7 @@ SharedPtr ServerSession::CreateClientSession() { return ClientSession::Create(SharedPtr(this), nullptr, name + "Client").MoveFrom(); } -std::tuple, SharedPtr> ServerSession::CreateSessionPair(SharedPtr client_port, std::string name) { +std::tuple, SharedPtr> ServerSession::CreateSessionPair(SharedPtr client_port, const std::string& name) { auto server_session = ServerSession::Create(name + "Server").MoveFrom(); auto client_session = ClientSession::Create(server_session, client_port, name + "Client").MoveFrom(); diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index eab9fe211..510b0a150 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -200,7 +200,7 @@ public: * @param name Optional name of the ports * @return The created session tuple */ - static std::tuple, SharedPtr> CreateSessionPair(SharedPtr client_port, std::string name = "Unknown"); + static std::tuple, SharedPtr> CreateSessionPair(SharedPtr client_port, const std::string& name = "Unknown"); /** * Creates a portless ClientSession and associates it with this ServerSession. diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index fd15ad03f..8df968b2e 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -40,7 +40,7 @@ public: * It should be overwritten by each service implementation for more fine-grained control. * @returns The maximum number of connections allowed. */ - virtual u32 GetMaxSessions() { return DefaultMaxSessions; } + virtual u32 GetMaxSessions() const { return DefaultMaxSessions; } void AddWaitingSession(Kernel::SharedPtr server_session) override { } From c19afd21188e91b9dd2780cf5cb9872a17ad113d Mon Sep 17 00:00:00 2001 From: Subv Date: Fri, 17 Jun 2016 17:09:43 -0500 Subject: [PATCH 03/18] Kernel/HLE: Service::Interface no longer inherits from any Kernel object, and is now its own standalone class. Interface is now used by aggregation in ClientPort, to forward service commands to their HLE implementation if needed. --- src/core/hle/kernel/client_port.cpp | 23 +++++++++++++++++++++++ src/core/hle/kernel/client_port.h | 29 +++++++++++++++++++++-------- src/core/hle/service/service.cpp | 12 ++++-------- src/core/hle/service/service.h | 12 ++++-------- 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 5ee7679eb..9a9cd4bfd 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -7,16 +7,39 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/service/service.h" namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} +Kernel::SharedPtr ClientPort::CreateForHLE(u32 max_sessions, std::unique_ptr hle_interface) { + SharedPtr client_port(new ClientPort); + client_port->max_sessions = max_sessions; + client_port->active_sessions = 0; + client_port->name = hle_interface->GetPortName(); + client_port->hle_interface = std::move(hle_interface); + + return client_port; +} + void ClientPort::AddWaitingSession(SharedPtr server_session) { + // A port that has an associated HLE interface doesn't have a server port. + if (hle_interface != nullptr) + return; + server_port->pending_sessions.push_back(server_session); // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); } +ResultCode ClientPort::HandleSyncRequest() { + // Forward the request to the associated HLE interface if it exists + if (hle_interface != nullptr) + return hle_interface->HandleSyncRequest(); + + return RESULT_SUCCESS; +} + } // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index eb0882870..ee65606ba 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -5,18 +5,31 @@ #pragma once #include +#include #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +namespace Service { +class Interface; +} + namespace Kernel { class ServerPort; class ServerSession; -class ClientPort : public Object { +class ClientPort final : public Object { public: friend class ServerPort; + /** + * Creates a serverless ClientPort that represents a bridge between the HLE implementation of a service/port and the emulated application. + * @param max_sessions Maximum number of sessions that this port is able to handle concurrently. + * @param hle_interface Interface object that implements the commands of the service. + * @returns ClientPort for the given HLE interface. + */ + static Kernel::SharedPtr CreateForHLE(u32 max_sessions, std::unique_ptr hle_interface); + /** * Adds the specified server session to the queue of pending sessions of the associated ServerPort * @param server_session Server session to add to the queue @@ -25,10 +38,9 @@ public: /** * Handle a sync request from the emulated application. - * Only HLE services should override this function. * @returns ResultCode from the operation. */ - virtual ResultCode HandleSyncRequest() { return RESULT_SUCCESS; } + ResultCode HandleSyncRequest(); std::string GetTypeName() const override { return "ClientPort"; } std::string GetName() const override { return name; } @@ -38,12 +50,13 @@ public: return HANDLE_TYPE; } - SharedPtr server_port; ///< ServerPort associated with this client port. - u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have - u32 active_sessions; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) + SharedPtr server_port = nullptr; ///< ServerPort associated with this client port. + u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have + u32 active_sessions; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) + std::unique_ptr hle_interface = nullptr; ///< HLE implementation of this port's request handler -protected: +private: ClientPort(); ~ClientPort() override; }; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index f51a042ff..abfc1806b 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -97,17 +97,13 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - interface_->name = interface_->GetPortName(); - interface_->active_sessions = 0; - interface_->max_sessions = interface_->GetMaxSessions(); - g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); + auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::unique_ptr(interface_)); + g_kernel_named_ports.emplace(interface_->GetPortName(), client_port); } void AddService(Interface* interface_) { - interface_->name = interface_->GetPortName(); - interface_->active_sessions = 0; - interface_->max_sessions = interface_->GetMaxSessions(); - g_srv_services.emplace(interface_->GetPortName(), interface_); + auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::unique_ptr(interface_)); + g_srv_services.emplace(interface_->GetPortName(), client_port); } /// Initialize ServiceManager diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 8df968b2e..b22caca07 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -22,18 +22,16 @@ static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 character static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE port /// Interface to a CTROS service -class Interface : public Kernel::ClientPort { - // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be - // just something that encapsulates a session and acts as a helper to implement service - // processes. +class Interface { public: - std::string GetName() const override { + std::string GetName() const { return GetPortName(); } virtual void SetVersion(u32 raw_version) { version.raw = raw_version; } + virtual ~Interface() {} /** * Gets the maximum allowed number of sessions that can be connected to this port at the same time. @@ -42,8 +40,6 @@ public: */ virtual u32 GetMaxSessions() const { return DefaultMaxSessions; } - void AddWaitingSession(Kernel::SharedPtr server_session) override { } - typedef void (*Function)(Interface*); struct FunctionInfo { @@ -60,7 +56,7 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultCode HandleSyncRequest() override; + ResultCode HandleSyncRequest(); protected: /** From c5e7e0fa26fc793c8b9f3effe25586f7fb57953e Mon Sep 17 00:00:00 2001 From: Subv Date: Sat, 18 Jun 2016 13:39:26 -0500 Subject: [PATCH 04/18] IPC/HLE: Associate the ClientSessions with their parent port's HLE interface if it exists. Pass the triggering ServerSession to the HLE command handler to differentiate which session caused the request. --- src/core/hle/kernel/client_port.cpp | 10 +--------- src/core/hle/kernel/client_port.h | 12 +++--------- src/core/hle/kernel/client_session.cpp | 9 +++++---- src/core/hle/kernel/client_session.h | 6 ++++++ src/core/hle/service/service.cpp | 8 +++++--- src/core/hle/service/service.h | 2 +- 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 9a9cd4bfd..0ac36cd12 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -14,7 +14,7 @@ namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} -Kernel::SharedPtr ClientPort::CreateForHLE(u32 max_sessions, std::unique_ptr hle_interface) { +Kernel::SharedPtr ClientPort::CreateForHLE(u32 max_sessions, std::shared_ptr hle_interface) { SharedPtr client_port(new ClientPort); client_port->max_sessions = max_sessions; client_port->active_sessions = 0; @@ -34,12 +34,4 @@ void ClientPort::AddWaitingSession(SharedPtr server_session) { server_port->WakeupAllWaitingThreads(); } -ResultCode ClientPort::HandleSyncRequest() { - // Forward the request to the associated HLE interface if it exists - if (hle_interface != nullptr) - return hle_interface->HandleSyncRequest(); - - return RESULT_SUCCESS; -} - } // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index ee65606ba..52308f13f 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -28,19 +28,13 @@ public: * @param hle_interface Interface object that implements the commands of the service. * @returns ClientPort for the given HLE interface. */ - static Kernel::SharedPtr CreateForHLE(u32 max_sessions, std::unique_ptr hle_interface); + static Kernel::SharedPtr CreateForHLE(u32 max_sessions, std::shared_ptr hle_interface); /** * Adds the specified server session to the queue of pending sessions of the associated ServerPort * @param server_session Server session to add to the queue */ - virtual void AddWaitingSession(SharedPtr server_session); - - /** - * Handle a sync request from the emulated application. - * @returns ResultCode from the operation. - */ - ResultCode HandleSyncRequest(); + void AddWaitingSession(SharedPtr server_session); std::string GetTypeName() const override { return "ClientPort"; } std::string GetName() const override { return name; } @@ -54,7 +48,7 @@ public: u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions; ///< Number of currently open sessions to this port std::string name; ///< Name of client port (optional) - std::unique_ptr hle_interface = nullptr; ///< HLE implementation of this port's request handler + std::shared_ptr hle_interface = nullptr; ///< HLE implementation of this port's request handler private: ClientPort(); diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index f1ad9b65b..22fa2ff03 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" namespace Kernel { @@ -20,6 +21,7 @@ ResultVal> ClientSession::Create(SharedPtrname = std::move(name); client_session->server_session = server_session; client_session->client_port = client_port; + client_session->hle_helper = client_port->hle_interface; return MakeResult>(std::move(client_session)); } @@ -31,10 +33,9 @@ ResultCode ClientSession::HandleSyncRequest() { if (result.IsError()) return result; - // Tell the client port to handle the request in case it's an HLE service. - // The client port can be nullptr for port-less sessions (Like for example File and Directory sessions). - if (client_port != nullptr) - result = client_port->HandleSyncRequest(); + // If this ClientSession has an associated HLE helper, forward the request to it. + if (hle_helper != nullptr) + result = hle_helper->HandleSyncRequest(server_session); return result; } diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 4fe9b4517..c2fc0d7dd 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -5,11 +5,16 @@ #pragma once #include +#include #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +namespace Service { +class Interface; +} + namespace Kernel { class ClientPort; @@ -41,6 +46,7 @@ public: std::string name; ///< Name of client port (optional) SharedPtr server_session; ///< The server session associated with this client session. SharedPtr client_port; ///< The client port which this session is connected to. + std::shared_ptr hle_helper = nullptr; ///< HLE implementation of this port's request handler private: ClientSession(); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index abfc1806b..56e4f8734 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -61,7 +61,9 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -ResultCode Interface::HandleSyncRequest() { +ResultCode Interface::HandleSyncRequest(Kernel::SharedPtr server_session) { + // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which session triggered each command. + u32* cmd_buff = Kernel::GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -97,12 +99,12 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::unique_ptr(interface_)); + auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::shared_ptr(interface_)); g_kernel_named_ports.emplace(interface_->GetPortName(), client_port); } void AddService(Interface* interface_) { - auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::unique_ptr(interface_)); + auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::shared_ptr(interface_)); g_srv_services.emplace(interface_->GetPortName(), client_port); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index b22caca07..e2d04450a 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -56,7 +56,7 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultCode HandleSyncRequest(); + ResultCode HandleSyncRequest(Kernel::SharedPtr server_session); protected: /** From 009b15b3aa9858930f461d825f7dd030fc963801 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 30 Nov 2016 22:50:13 -0500 Subject: [PATCH 05/18] A bit of a redesign. Sessions and Ports are now detached from each other. HLE services are handled by means of a SessionRequestHandler class, Interface now inherits from this class. The File and Directory classes are no longer kernel objects, but SessionRequestHandlers instead, bound to a ServerSession when requested. File::OpenLinkFile now creates a new session pair and binds the File instance to it. --- src/core/hle/kernel/client_port.cpp | 14 -- src/core/hle/kernel/client_port.h | 12 +- src/core/hle/kernel/client_session.cpp | 16 +-- src/core/hle/kernel/client_session.h | 5 +- src/core/hle/kernel/server_session.cpp | 25 ++-- src/core/hle/kernel/server_session.h | 167 ++--------------------- src/core/hle/service/fs/archive.cpp | 35 ++--- src/core/hle/service/fs/archive.h | 20 +-- src/core/hle/service/fs/fs_user.cpp | 18 ++- src/core/hle/service/service.cpp | 17 ++- src/core/hle/service/service.h | 179 ++++++++++++++++++++++++- src/core/hle/service/srv.cpp | 10 +- src/core/hle/svc.cpp | 11 +- 13 files changed, 266 insertions(+), 263 deletions(-) diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 0ac36cd12..de67688c9 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -14,21 +14,7 @@ namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} -Kernel::SharedPtr ClientPort::CreateForHLE(u32 max_sessions, std::shared_ptr hle_interface) { - SharedPtr client_port(new ClientPort); - client_port->max_sessions = max_sessions; - client_port->active_sessions = 0; - client_port->name = hle_interface->GetPortName(); - client_port->hle_interface = std::move(hle_interface); - - return client_port; -} - void ClientPort::AddWaitingSession(SharedPtr server_session) { - // A port that has an associated HLE interface doesn't have a server port. - if (hle_interface != nullptr) - return; - server_port->pending_sessions.push_back(server_session); // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 52308f13f..7a53c93b8 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -22,14 +22,6 @@ class ClientPort final : public Object { public: friend class ServerPort; - /** - * Creates a serverless ClientPort that represents a bridge between the HLE implementation of a service/port and the emulated application. - * @param max_sessions Maximum number of sessions that this port is able to handle concurrently. - * @param hle_interface Interface object that implements the commands of the service. - * @returns ClientPort for the given HLE interface. - */ - static Kernel::SharedPtr CreateForHLE(u32 max_sessions, std::shared_ptr hle_interface); - /** * Adds the specified server session to the queue of pending sessions of the associated ServerPort * @param server_session Server session to add to the queue @@ -44,12 +36,10 @@ public: return HANDLE_TYPE; } - SharedPtr server_port = nullptr; ///< ServerPort associated with this client port. + SharedPtr server_port; ///< ServerPort associated with this client port. u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions; ///< Number of currently open sessions to this port std::string name; ///< Name of client port (optional) - std::shared_ptr hle_interface = nullptr; ///< HLE implementation of this port's request handler - private: ClientPort(); ~ClientPort() override; diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 22fa2ff03..31ea8045a 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -15,29 +15,17 @@ namespace Kernel { ClientSession::ClientSession() {} ClientSession::~ClientSession() {} -ResultVal> ClientSession::Create(SharedPtr server_session, SharedPtr client_port, std::string name) { +ResultVal> ClientSession::Create(SharedPtr server_session, std::string name) { SharedPtr client_session(new ClientSession); client_session->name = std::move(name); client_session->server_session = server_session; - client_session->client_port = client_port; - client_session->hle_helper = client_port->hle_interface; - return MakeResult>(std::move(client_session)); } ResultCode ClientSession::HandleSyncRequest() { // Signal the server session that new data is available - ResultCode result = server_session->HandleSyncRequest(); - - if (result.IsError()) - return result; - - // If this ClientSession has an associated HLE helper, forward the request to it. - if (hle_helper != nullptr) - result = hle_helper->HandleSyncRequest(server_session); - - return result; + return server_session->HandleSyncRequest(); } } // namespace diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index c2fc0d7dd..a951ea4d6 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -25,11 +25,10 @@ public: /** * Creates a client session. * @param server_session The server session associated with this client session - * @param client_port The client port which this session is connected to * @param name Optional name of client session * @return The created client session */ - static ResultVal> Create(SharedPtr server_session, SharedPtr client_port, std::string name = "Unknown"); + static ResultVal> Create(SharedPtr server_session, std::string name = "Unknown"); std::string GetTypeName() const override { return "ClientSession"; } std::string GetName() const override { return name; } @@ -45,8 +44,6 @@ public: std::string name; ///< Name of client port (optional) SharedPtr server_session; ///< The server session associated with this client session. - SharedPtr client_port; ///< The client port which this session is connected to. - std::shared_ptr hle_helper = nullptr; ///< HLE implementation of this port's request handler private: ClientSession(); diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 720c0eb94..200a7b815 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -14,11 +14,12 @@ namespace Kernel { ServerSession::ServerSession() {} ServerSession::~ServerSession() {} -ResultVal> ServerSession::Create(std::string name) { +ResultVal> ServerSession::Create(std::string name, std::shared_ptr hle_handler) { SharedPtr server_session(new ServerSession); server_session->name = std::move(name); server_session->signaled = false; + server_session->hle_handler = hle_handler; return MakeResult>(std::move(server_session)); } @@ -34,23 +35,21 @@ void ServerSession::Acquire() { ResultCode ServerSession::HandleSyncRequest() { // The ServerSession received a sync request, this means that there's new data available - // from one of its ClientSessions, so wake up any threads that may be waiting on a svcReplyAndReceive or similar. + // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or similar. + + // If this ServerSession has an associated HLE handler, forward the request to it. + if (hle_handler != nullptr) + return hle_handler->HandleSyncRequest(SharedPtr(this)); + + // If this ServerSession does not have an HLE implementation, just wake up the threads waiting on it. signaled = true; WakeupAllWaitingThreads(); return RESULT_SUCCESS; } -SharedPtr ServerSession::CreateClientSession() { - // In Citra, some types of ServerSessions (File and Directory sessions) are not created as a pair of Server-Client sessions, - // but are instead created as a single ServerSession, which then hands over a ClientSession on demand (When opening the File or Directory). - // The real kernel (Or more specifically, the real FS service) does create the pair of Sessions at the same time (via svcCreateSession), and simply - // stores the ClientSession until it is needed. - return ClientSession::Create(SharedPtr(this), nullptr, name + "Client").MoveFrom(); -} - -std::tuple, SharedPtr> ServerSession::CreateSessionPair(SharedPtr client_port, const std::string& name) { - auto server_session = ServerSession::Create(name + "Server").MoveFrom(); - auto client_session = ClientSession::Create(server_session, client_port, name + "Client").MoveFrom(); +std::tuple, SharedPtr> ServerSession::CreateSessionPair(const std::string& name, std::shared_ptr hle_handler) { + auto server_session = ServerSession::Create(name + "Server", hle_handler).MoveFrom(); + auto client_session = ClientSession::Create(server_session, name + "Client").MoveFrom(); return std::make_tuple(server_session, client_session); } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 510b0a150..86fe641c0 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -10,158 +10,11 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" #include "core/hle/result.h" +#include "core/hle/service/service.h" #include "core/memory.h" -namespace IPC { - -enum DescriptorType : u32 { - // Buffer related desciptors types (mask : 0x0F) - StaticBuffer = 0x02, - PXIBuffer = 0x04, - MappedBuffer = 0x08, - // Handle related descriptors types (mask : 0x30, but need to check for buffer related - // descriptors first ) - CopyHandle = 0x00, - MoveHandle = 0x10, - CallingPid = 0x20, -}; - -/** - * @brief Creates a command header to be used for IPC - * @param command_id ID of the command to create a header for. - * @param normal_params Size of the normal parameters in words. Up to 63. - * @param translate_params_size Size of the translate parameters in words. Up to 63. - * @return The created IPC header. - * - * Normal parameters are sent directly to the process while the translate parameters might go - * through modifications and checks by the kernel. - * The translate parameters are described by headers generated with the IPC::*Desc functions. - * - * @note While #normal_params is equivalent to the number of normal parameters, - * #translate_params_size includes the size occupied by the translate parameters headers. - */ -constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, - unsigned int translate_params_size) { - return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | - (u32(translate_params_size) & 0x3F); -} - -union Header { - u32 raw; - BitField<0, 6, u32> translate_params_size; - BitField<6, 6, u32> normal_params; - BitField<16, 16, u32> command_id; -}; - -inline Header ParseHeader(u32 header) { - return {header}; -} - -constexpr u32 MoveHandleDesc(u32 num_handles = 1) { - return MoveHandle | ((num_handles - 1) << 26); -} - -constexpr u32 CopyHandleDesc(u32 num_handles = 1) { - return CopyHandle | ((num_handles - 1) << 26); -} - -constexpr u32 CallingPidDesc() { - return CallingPid; -} - -constexpr bool isHandleDescriptor(u32 descriptor) { - return (descriptor & 0xF) == 0x0; -} - -constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) { - return (handle_descriptor >> 26) + 1; -} - -constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) { - return StaticBuffer | (size << 14) | ((buffer_id & 0xF) << 10); -} - -union StaticBufferDescInfo { - u32 raw; - BitField<10, 4, u32> buffer_id; - BitField<14, 18, u32> size; -}; - -inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { - return {desc}; -} - -/** - * @brief Creates a header describing a buffer to be sent over PXI. - * @param size Size of the buffer. Max 0x00FFFFFF. - * @param buffer_id The Id of the buffer. Max 0xF. - * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have - * read-write access. - * @return The created PXI buffer header. - * - * The next value is a phys-address of a table located in the BASE memregion. - */ -inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { - u32 type = PXIBuffer; - if (is_read_only) - type |= 0x2; - return type | (size << 8) | ((buffer_id & 0xF) << 4); -} - -enum MappedBufferPermissions { - R = 1, - W = 2, - RW = R | W, -}; - -constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { - return MappedBuffer | (size << 4) | (u32(perms) << 1); -} - -union MappedBufferDescInfo { - u32 raw; - BitField<4, 28, u32> size; - BitField<1, 2, MappedBufferPermissions> perms; -}; - -inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { - return {desc}; -} - -inline DescriptorType GetDescriptorType(u32 descriptor) { - // Note: Those checks must be done in this order - if (isHandleDescriptor(descriptor)) - return (DescriptorType)(descriptor & 0x30); - - // handle the fact that the following descriptors can have rights - if (descriptor & MappedBuffer) - return MappedBuffer; - - if (descriptor & PXIBuffer) - return PXIBuffer; - - return StaticBuffer; -} - -} // namespace IPC - namespace Kernel { -static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header - -/** - * Returns a pointer to the command buffer in the current thread's TLS - * TODO(Subv): This is not entirely correct, the command buffer should be copied from - * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to - * the service handler process' memory. - * @param offset Optional offset into command buffer - * @return Pointer to command buffer - */ -inline u32* GetCommandBuffer(const int offset = 0) { - return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + - offset); -} - class ClientSession; class ClientPort; @@ -183,11 +36,13 @@ public: ~ServerSession() override; /** - * Creates a server session. - * @param name Optional name of the server session + * Creates a server session. The server session can have an optional HLE handler, + * which will be invoked to handle the IPC requests that this session receives. + * @param name Optional name of the server session. + * @param hle_handler Optional HLE handler for this server session. * @return The created server session */ - static ResultVal> Create(std::string name = "Unknown"); + static ResultVal> Create(std::string name = "Unknown", std::shared_ptr hle_handler = nullptr); std::string GetTypeName() const override { return "ServerSession"; } @@ -196,17 +51,10 @@ public: /** * Creates a pair of ServerSession and an associated ClientSession. - * @param client_port ClientPort to which the sessions are connected * @param name Optional name of the ports * @return The created session tuple */ - static std::tuple, SharedPtr> CreateSessionPair(SharedPtr client_port, const std::string& name = "Unknown"); - - /** - * Creates a portless ClientSession and associates it with this ServerSession. - * @returns ClientSession The newly created ClientSession. - */ - SharedPtr CreateClientSession(); + static std::tuple, SharedPtr> CreateSessionPair(const std::string& name = "Unknown", std::shared_ptr hle_handler = nullptr); /** * Handle a sync request from the emulated application. @@ -221,5 +69,6 @@ public: std::string name; ///< The name of this session (optional) bool signaled; ///< Whether there's new data available to this ServerSession + std::shared_ptr hle_handler; ///< This session's HLE request handler (optional) }; } diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index da009df91..e40483c72 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -23,10 +23,11 @@ #include "core/file_sys/directory_backend.h" #include "core/file_sys/file_backend.h" #include "core/hle/hle.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/result.h" +#include "core/hle/service/service.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" -#include "core/hle/service/service.h" #include "core/memory.h" // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. @@ -92,11 +93,10 @@ File::File(std::unique_ptr&& backend, const FileSys::Path& File::~File() {} -ResultCode File::HandleSyncRequest() { +ResultCode File::HandleSyncRequest(Kernel::SharedPtr server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { - // Read from file... case FileCommand::Read: { u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32; @@ -170,9 +170,11 @@ ResultCode File::HandleSyncRequest() { break; } - case FileCommand::OpenLinkFile: { + case FileCommand::OpenLinkFile: + { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); - cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE); + auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); + cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).ValueOr(INVALID_HANDLE); break; } @@ -193,10 +195,10 @@ ResultCode File::HandleSyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return ServerSession::HandleSyncRequest(); + return RESULT_SUCCESS; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return ServerSession::HandleSyncRequest(); + return RESULT_SUCCESS; } Directory::Directory(std::unique_ptr&& backend, @@ -205,11 +207,10 @@ Directory::Directory(std::unique_ptr&& backend, Directory::~Directory() {} -ResultCode Directory::HandleSyncRequest() { +ResultCode Directory::HandleSyncRequest(Kernel::SharedPtr server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); DirectoryCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { - // Read from directory... case DirectoryCommand::Read: { u32 count = cmd_buff[1]; @@ -236,10 +237,10 @@ ResultCode Directory::HandleSyncRequest() { LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return ServerSession::HandleSyncRequest(); + return RESULT_SUCCESS; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return ServerSession::HandleSyncRequest(); + return RESULT_SUCCESS; } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -306,7 +307,7 @@ ResultCode RegisterArchiveType(std::unique_ptr&& factor return RESULT_SUCCESS; } -ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, +ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); @@ -317,8 +318,8 @@ ResultVal> OpenFileFromArchive(ArchiveHandle archive_han if (backend.Failed()) return backend.Code(); - auto file = Kernel::SharedPtr(new File(backend.MoveFrom(), path)); - return MakeResult>(std::move(file)); + auto file = std::shared_ptr(new File(backend.MoveFrom(), path)); + return MakeResult>(std::move(file)); } ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { @@ -397,7 +398,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, } } -ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, +ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) @@ -407,8 +408,8 @@ ResultVal> OpenDirectoryFromArchive(ArchiveHandle a if (backend.Failed()) return backend.Code(); - auto directory = Kernel::SharedPtr(new Directory(backend.MoveFrom(), path)); - return MakeResult>(std::move(directory)); + auto directory = std::shared_ptr(new Directory(backend.MoveFrom(), path)); + return MakeResult>(std::move(directory)); } ResultVal GetFreeBytesInArchive(ArchiveHandle archive_handle) { diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 22e659c40..29527ef48 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -41,32 +41,32 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1 }; typedef u64 ArchiveHandle; -class File : public Kernel::ServerSession { +class File : public SessionRequestHandler, public std::enable_shared_from_this { public: File(std::unique_ptr&& backend, const FileSys::Path& path); ~File(); - std::string GetName() const override { + std::string GetName() const { return "Path: " + path.DebugStr(); } - ResultCode HandleSyncRequest() override; + ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) override; FileSys::Path path; ///< Path of the file u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means std::unique_ptr backend; ///< File backend interface }; -class Directory : public Kernel::ServerSession { +class Directory : public SessionRequestHandler { public: Directory(std::unique_ptr&& backend, const FileSys::Path& path); ~Directory(); - std::string GetName() const override { + std::string GetName() const { return "Directory: " + path.DebugStr(); } - ResultCode HandleSyncRequest() override; + ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) override; FileSys::Path path; ///< Path of the directory std::unique_ptr backend; ///< File backend interface @@ -99,9 +99,9 @@ ResultCode RegisterArchiveType(std::unique_ptr&& factor * @param archive_handle Handle to an open Archive object * @param path Path to the File inside of the Archive * @param mode Mode under which to open the File - * @return The opened File object as a Session + * @return The opened File object */ -ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, +ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); @@ -178,9 +178,9 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return The opened Directory object as a Session + * @return The opened Directory object */ -ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, +ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); /** diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index bb78091f9..a29bce22a 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -68,10 +68,12 @@ static void OpenFile(Service::Interface* self) { LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - ResultVal> file_res = OpenFileFromArchive(archive_handle, file_path, mode); + ResultVal> file_res = OpenFileFromArchive(archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create((*file_res)->CreateClientSession()).MoveFrom(); + std::shared_ptr file = *file_res; + auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -128,10 +130,12 @@ static void OpenFileDirectly(Service::Interface* self) { } SCOPE_EXIT({ CloseArchive(*archive_handle); }); - ResultVal> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); + ResultVal> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create((*file_res)->CreateClientSession()).MoveFrom(); + std::shared_ptr file = *file_res; + auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", @@ -389,10 +393,12 @@ static void OpenDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast(dirname_type), dirname_size, dir_path.DebugStr().c_str()); - ResultVal> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); + ResultVal> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); cmd_buff[1] = dir_res.Code().raw; if (dir_res.Succeeded()) { - cmd_buff[3] = Kernel::g_handle_table.Create((*dir_res)->CreateClientSession()).MoveFrom(); + std::shared_ptr directory = *dir_res; + auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); + cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 56e4f8734..c90802455 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -4,6 +4,9 @@ #include "common/logging/log.h" #include "common/string_util.h" + +#include "core/hle/kernel/server_port.h" +#include "core/hle/service/service.h" #include "core/hle/service/ac_u.h" #include "core/hle/service/act_a.h" #include "core/hle/service/act_u.h" @@ -41,8 +44,8 @@ namespace Service { -std::unordered_map> g_kernel_named_ports; -std::unordered_map> g_srv_services; +std::unordered_map, std::shared_ptr>> g_kernel_named_ports; +std::unordered_map, std::shared_ptr>> g_srv_services; /** * Creates a function string for logging, complete with the name (or header code, depending @@ -99,13 +102,15 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::shared_ptr(interface_)); - g_kernel_named_ports.emplace(interface_->GetPortName(), client_port); + auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); + auto client_port = std::get>(ports); + g_kernel_named_ports.emplace(interface_->GetPortName(), std::make_tuple(client_port, std::shared_ptr(interface_))); } void AddService(Interface* interface_) { - auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::shared_ptr(interface_)); - g_srv_services.emplace(interface_->GetPortName(), client_port); + auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); + auto client_port = std::get>(ports); + g_srv_services.emplace(interface_->GetPortName(), std::make_tuple(client_port, std::shared_ptr(interface_))); } /// Initialize ServiceManager diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index e2d04450a..dd268f39c 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -10,8 +10,163 @@ #include #include "common/common_types.h" #include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/thread.h" #include "core/hle/result.h" +#include "core/memory.h" + +namespace Kernel { +class ServerSession; + +// TODO(Subv): Move these declarations out of here +static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header + +/** + * Returns a pointer to the command buffer in the current thread's TLS + * TODO(Subv): This is not entirely correct, the command buffer should be copied from + * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to + * the service handler process' memory. + * @param offset Optional offset into command buffer + * @return Pointer to command buffer + */ +inline u32* GetCommandBuffer(const int offset = 0) { + return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + + offset); +} +} + +// TODO(Subv): Move this namespace out of here +namespace IPC { + +enum DescriptorType : u32 { + // Buffer related desciptors types (mask : 0x0F) + StaticBuffer = 0x02, + PXIBuffer = 0x04, + MappedBuffer = 0x08, + // Handle related descriptors types (mask : 0x30, but need to check for buffer related + // descriptors first ) + CopyHandle = 0x00, + MoveHandle = 0x10, + CallingPid = 0x20, +}; + +/** +* @brief Creates a command header to be used for IPC +* @param command_id ID of the command to create a header for. +* @param normal_params Size of the normal parameters in words. Up to 63. +* @param translate_params_size Size of the translate parameters in words. Up to 63. +* @return The created IPC header. +* +* Normal parameters are sent directly to the process while the translate parameters might go +* through modifications and checks by the kernel. +* The translate parameters are described by headers generated with the IPC::*Desc functions. +* +* @note While #normal_params is equivalent to the number of normal parameters, +* #translate_params_size includes the size occupied by the translate parameters headers. +*/ +constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, + unsigned int translate_params_size) { + return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | + (u32(translate_params_size) & 0x3F); +} + +union Header { + u32 raw; + BitField<0, 6, u32> translate_params_size; + BitField<6, 6, u32> normal_params; + BitField<16, 16, u32> command_id; +}; + +inline Header ParseHeader(u32 header) { + return{ header }; +} + +constexpr u32 MoveHandleDesc(u32 num_handles = 1) { + return MoveHandle | ((num_handles - 1) << 26); +} + +constexpr u32 CopyHandleDesc(u32 num_handles = 1) { + return CopyHandle | ((num_handles - 1) << 26); +} + +constexpr u32 CallingPidDesc() { + return CallingPid; +} + +constexpr bool isHandleDescriptor(u32 descriptor) { + return (descriptor & 0xF) == 0x0; +} + +constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) { + return (handle_descriptor >> 26) + 1; +} + +constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) { + return StaticBuffer | (size << 14) | ((buffer_id & 0xF) << 10); +} + +union StaticBufferDescInfo { + u32 raw; + BitField<10, 4, u32> buffer_id; + BitField<14, 18, u32> size; +}; + +inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { + return{ desc }; +} + +/** +* @brief Creates a header describing a buffer to be sent over PXI. +* @param size Size of the buffer. Max 0x00FFFFFF. +* @param buffer_id The Id of the buffer. Max 0xF. +* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have +* read-write access. +* @return The created PXI buffer header. +* +* The next value is a phys-address of a table located in the BASE memregion. +*/ +inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { + u32 type = PXIBuffer; + if (is_read_only) + type |= 0x2; + return type | (size << 8) | ((buffer_id & 0xF) << 4); +} + +enum MappedBufferPermissions { + R = 1, + W = 2, + RW = R | W, +}; + +constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { + return MappedBuffer | (size << 4) | (u32(perms) << 1); +} + +union MappedBufferDescInfo { + u32 raw; + BitField<4, 28, u32> size; + BitField<1, 2, MappedBufferPermissions> perms; +}; + +inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { + return{ desc }; +} + +inline DescriptorType GetDescriptorType(u32 descriptor) { + // Note: Those checks must be done in this order + if (isHandleDescriptor(descriptor)) + return (DescriptorType)(descriptor & 0x30); + + // handle the fact that the following descriptors can have rights + if (descriptor & MappedBuffer) + return MappedBuffer; + + if (descriptor & PXIBuffer) + return PXIBuffer; + + return StaticBuffer; +} + +} // namespace IPC //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service @@ -21,8 +176,22 @@ namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE port +/// TODO(Subv): Write documentation for this class +class SessionRequestHandler { +public: + /** + * Dispatches and handles a sync request from the emulated application. + * @param server_session The ServerSession that was triggered for this sync request, + * it should be used to differentiate which client (As in ClientSession) we're answering to. + * TODO(Subv): Make a HandleSyncRequestParent function that is called from the outside and does { ReturnIfError(Translate()); HandleSyncRequest(); } + * The Translate() function would copy the command buffer from the ServerSession thread's TLS into a temporary buffer, and pass it to HandleSyncRequest. + * TODO(Subv): HandleSyncRequest's return type should be void. + */ + virtual ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) = 0; +}; + /// Interface to a CTROS service -class Interface { +class Interface : public SessionRequestHandler { public: std::string GetName() const { return GetPortName(); @@ -56,7 +225,7 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultCode HandleSyncRequest(Kernel::SharedPtr server_session); + ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) override; protected: /** @@ -88,9 +257,9 @@ void Init(); void Shutdown(); /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. -extern std::unordered_map> g_kernel_named_ports; +extern std::unordered_map, std::shared_ptr>> g_kernel_named_ports; /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map> g_srv_services; +extern std::unordered_map, std::shared_ptr>> g_srv_services; /// Adds a service to the services table void AddService(Interface* interface_); diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index eb2e06041..6731afc22 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -10,6 +10,7 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/event.h" #include "core/hle/service/srv.h" +#include "core/hle/kernel/server_session.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace SRV @@ -85,13 +86,18 @@ static void GetServiceHandle(Service::Interface* self) { auto it = Service::g_srv_services.find(port_name); if (it != Service::g_srv_services.end()) { - auto client_port = it->second; + auto client_port = std::get>(it->second); + // The hle_handler will be nullptr if this port was registered by the emulated + // application by means of srv:RegisterService. + auto hle_handler = std::get>(it->second); // Create a new session pair - auto sessions = Kernel::ServerSession::CreateSessionPair(client_port, port_name); + auto sessions = Kernel::ServerSession::CreateSessionPair(port_name, hle_handler); auto client_session = std::get>(sessions); auto server_session = std::get>(sessions); + // TODO(Subv): Wait the current thread until the ServerPort calls AcceptSession. + // Add the server session to the port's queue client_port->AddWaitingSession(server_session); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index be03e53bc..6d990b5f2 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -21,6 +21,7 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -223,13 +224,18 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { return ERR_NOT_FOUND; } - auto client_port = it->second; + auto client_port = std::get>(it->second); + // The hle_handler will be nullptr if this port was registered by the emulated + // application by means of svcCreatePort with a defined name. + auto hle_handler = std::get>(it->second); // Create a new session pair - auto sessions = Kernel::ServerSession::CreateSessionPair(client_port, port_name); + auto sessions = Kernel::ServerSession::CreateSessionPair(port_name, hle_handler); auto client_session = std::get>(sessions); auto server_session = std::get>(sessions); + // TODO(Subv): Wait the current thread until the ServerPort calls AcceptSession. + // Add the server session to the port's queue client_port->AddWaitingSession(server_session); @@ -247,6 +253,7 @@ static ResultCode SendSyncRequest(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); + // TODO(Subv): Wait the current thread and reschedule if this request is not going to be handled by HLE code. return session->HandleSyncRequest(); } From 2eceee3a4cc2786dae4e9b80a8b5f3bb666d3fc6 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 30 Nov 2016 23:28:31 -0500 Subject: [PATCH 06/18] Fixed the rebase mistakes. --- src/citra_qt/debugger/wait_tree.cpp | 1 - src/core/hle/kernel/client_port.cpp | 1 - src/core/hle/kernel/client_port.h | 32 ++++++++--------- src/core/hle/kernel/client_session.cpp | 3 -- src/core/hle/kernel/client_session.h | 17 ++++----- src/core/hle/kernel/kernel.h | 34 +++++++++--------- src/core/hle/kernel/server_session.cpp | 1 - src/core/hle/kernel/server_session.h | 9 +++-- src/core/hle/service/fs/archive.cpp | 8 ++--- src/core/hle/service/service.h | 50 +++++++++++++------------- src/core/hle/service/srv.cpp | 3 +- 11 files changed, 76 insertions(+), 83 deletions(-) diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp index be5a51e52..51e70fae3 100644 --- a/src/citra_qt/debugger/wait_tree.cpp +++ b/src/citra_qt/debugger/wait_tree.cpp @@ -8,7 +8,6 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/semaphore.h" -#include "core/hle/kernel/session.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index de67688c9..5ee7679eb 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -7,7 +7,6 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" -#include "core/hle/service/service.h" namespace Kernel { diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 7a53c93b8..4848cb4c4 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -5,14 +5,9 @@ #pragma once #include -#include #include "common/common_types.h" #include "core/hle/kernel/kernel.h" -namespace Service { -class Interface; -} - namespace Kernel { class ServerPort; @@ -21,6 +16,17 @@ class ServerSession; class ClientPort final : public Object { public: friend class ServerPort; + std::string GetTypeName() const override { + return "ClientPort"; + } + std::string GetName() const override { + return name; + } + + static const HandleType HANDLE_TYPE = HandleType::ClientPort; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } /** * Adds the specified server session to the queue of pending sessions of the associated ServerPort @@ -28,18 +34,10 @@ public: */ void AddWaitingSession(SharedPtr server_session); - std::string GetTypeName() const override { return "ClientPort"; } - std::string GetName() const override { return name; } - - static const HandleType HANDLE_TYPE = HandleType::ClientPort; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - SharedPtr server_port; ///< ServerPort associated with this client port. - u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have - u32 active_sessions; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) + SharedPtr server_port; ///< ServerPort associated with this client port. + u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have + u32 active_sessions; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) private: ClientPort(); ~ClientPort() override; diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 31ea8045a..c8be29b0a 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -4,11 +4,8 @@ #include "common/assert.h" -#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/service/service.h" namespace Kernel { diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index a951ea4d6..e34528301 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -11,13 +11,8 @@ #include "core/hle/kernel/kernel.h" -namespace Service { -class Interface; -} - namespace Kernel { -class ClientPort; class ServerSession; class ClientSession final : public Object { @@ -30,11 +25,17 @@ public: */ static ResultVal> Create(SharedPtr server_session, std::string name = "Unknown"); - std::string GetTypeName() const override { return "ClientSession"; } - std::string GetName() const override { return name; } + std::string GetTypeName() const override { + return "ClientSession"; + } + std::string GetName() const override { + return name; + } static const HandleType HANDLE_TYPE = HandleType::ClientSession; - HandleType GetHandleType() const override { return HANDLE_TYPE; } + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } /** * Handle a SyncRequest from the emulated application. diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4bd505b5d..9808d375b 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -31,24 +31,22 @@ enum KernelHandle : Handle { }; enum class HandleType : u32 { - Unknown = 0, - - - Event = 3, - Mutex = 4, - SharedMemory = 5, - Redirection = 6, - Thread = 7, - Process = 8, - AddressArbiter = 9, - Semaphore = 10, - Timer = 11, - ResourceLimit = 12, - CodeSet = 13, - ClientPort = 14, - ServerPort = 15, - ClientSession = 16, - ServerSession = 17, + Unknown, + Event, + Mutex, + SharedMemory, + Redirection, + Thread, + Process, + AddressArbiter, + Semaphore, + Timer, + ResourceLimit, + CodeSet, + ClientPort, + ServerPort, + ClientSession, + ServerSession, }; enum { diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 200a7b815..006d67e65 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -4,7 +4,6 @@ #include -#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/thread.h" diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 86fe641c0..70661e9af 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -16,7 +16,6 @@ namespace Kernel { class ClientSession; -class ClientPort; /** * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS @@ -44,10 +43,14 @@ public: */ static ResultVal> Create(std::string name = "Unknown", std::shared_ptr hle_handler = nullptr); - std::string GetTypeName() const override { return "ServerSession"; } + std::string GetTypeName() const override { + return "ServerSession"; + } static const HandleType HANDLE_TYPE = HandleType::ServerSession; - HandleType GetHandleType() const override { return HANDLE_TYPE; } + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } /** * Creates a pair of ServerSession and an associated ClientSession. diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index e40483c72..a9f457726 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -25,9 +25,9 @@ #include "core/hle/hle.h" #include "core/hle/kernel/client_session.h" #include "core/hle/result.h" -#include "core/hle/service/service.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/fs_user.h" +#include "core/hle/service/service.h" #include "core/memory.h" // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. @@ -97,6 +97,7 @@ ResultCode File::HandleSyncRequest(Kernel::SharedPtr serv u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { + // Read from file... case FileCommand::Read: { u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32; @@ -170,8 +171,7 @@ ResultCode File::HandleSyncRequest(Kernel::SharedPtr serv break; } - case FileCommand::OpenLinkFile: - { + case FileCommand::OpenLinkFile: { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).ValueOr(INVALID_HANDLE); @@ -195,7 +195,7 @@ ResultCode File::HandleSyncRequest(Kernel::SharedPtr serv LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return RESULT_SUCCESS; + return error; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error return RESULT_SUCCESS; diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index dd268f39c..931512339 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -50,23 +50,23 @@ enum DescriptorType : u32 { }; /** -* @brief Creates a command header to be used for IPC -* @param command_id ID of the command to create a header for. -* @param normal_params Size of the normal parameters in words. Up to 63. -* @param translate_params_size Size of the translate parameters in words. Up to 63. -* @return The created IPC header. -* -* Normal parameters are sent directly to the process while the translate parameters might go -* through modifications and checks by the kernel. -* The translate parameters are described by headers generated with the IPC::*Desc functions. -* -* @note While #normal_params is equivalent to the number of normal parameters, -* #translate_params_size includes the size occupied by the translate parameters headers. -*/ + * @brief Creates a command header to be used for IPC + * @param command_id ID of the command to create a header for. + * @param normal_params Size of the normal parameters in words. Up to 63. + * @param translate_params_size Size of the translate parameters in words. Up to 63. + * @return The created IPC header. + * + * Normal parameters are sent directly to the process while the translate parameters might go + * through modifications and checks by the kernel. + * The translate parameters are described by headers generated with the IPC::*Desc functions. + * + * @note While #normal_params is equivalent to the number of normal parameters, + * #translate_params_size includes the size occupied by the translate parameters headers. + */ constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, unsigned int translate_params_size) { return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | - (u32(translate_params_size) & 0x3F); + (u32(translate_params_size) & 0x3F); } union Header { @@ -77,7 +77,7 @@ union Header { }; inline Header ParseHeader(u32 header) { - return{ header }; + return {header}; } constexpr u32 MoveHandleDesc(u32 num_handles = 1) { @@ -111,19 +111,19 @@ union StaticBufferDescInfo { }; inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { - return{ desc }; + return {desc}; } /** -* @brief Creates a header describing a buffer to be sent over PXI. -* @param size Size of the buffer. Max 0x00FFFFFF. -* @param buffer_id The Id of the buffer. Max 0xF. -* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have -* read-write access. -* @return The created PXI buffer header. -* -* The next value is a phys-address of a table located in the BASE memregion. -*/ + * @brief Creates a header describing a buffer to be sent over PXI. + * @param size Size of the buffer. Max 0x00FFFFFF. + * @param buffer_id The Id of the buffer. Max 0xF. + * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have + * read-write access. + * @return The created PXI buffer header. + * + * The next value is a phys-address of a table located in the BASE memregion. + */ inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { u32 type = PXIBuffer; if (is_read_only) diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 6731afc22..d228e3523 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -6,11 +6,10 @@ #include "common/common_types.h" #include "common/logging/log.h" -#include "core/hle/service/srv.h" #include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/event.h" #include "core/hle/service/srv.h" -#include "core/hle/kernel/server_session.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace SRV From ed210c32b3820c77845c27d1f73e6ff2f0828505 Mon Sep 17 00:00:00 2001 From: Subv Date: Thu, 1 Dec 2016 10:47:06 -0500 Subject: [PATCH 07/18] Threads do not wait for the server endpoint to call AcceptSession before returning from a ConnectToPort or GetServiceHandle call. --- src/core/hle/service/srv.cpp | 3 ++- src/core/hle/svc.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index d228e3523..c0abfd711 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -95,7 +95,8 @@ static void GetServiceHandle(Service::Interface* self) { auto client_session = std::get>(sessions); auto server_session = std::get>(sessions); - // TODO(Subv): Wait the current thread until the ServerPort calls AcceptSession. + // Note: Threads do not wait for the server endpoint to call + // AcceptSession before returning from this call. // Add the server session to the port's queue client_port->AddWaitingSession(server_session); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 6d990b5f2..ab0eb9d86 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -234,11 +234,12 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { auto client_session = std::get>(sessions); auto server_session = std::get>(sessions); - // TODO(Subv): Wait the current thread until the ServerPort calls AcceptSession. - // Add the server session to the port's queue client_port->AddWaitingSession(server_session); + // Note: Threads do not wait for the server endpoint to call + // AcceptSession before returning from this call. + // Return the client session CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session)); return RESULT_SUCCESS; From 2ce61344d612b8574e12d8acdf59ac994b390ab5 Mon Sep 17 00:00:00 2001 From: Subv Date: Fri, 2 Dec 2016 22:58:02 -0500 Subject: [PATCH 08/18] Declare empty ServerSession and ClientSession constructors as default. --- src/core/hle/kernel/client_session.cpp | 4 ++-- src/core/hle/kernel/server_session.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index c8be29b0a..c90fbc69d 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -9,8 +9,8 @@ namespace Kernel { -ClientSession::ClientSession() {} -ClientSession::~ClientSession() {} +ClientSession::ClientSession() = default; +ClientSession::~ClientSession() = default; ResultVal> ClientSession::Create(SharedPtr server_session, std::string name) { SharedPtr client_session(new ClientSession); diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 006d67e65..be334efd7 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -10,8 +10,8 @@ namespace Kernel { -ServerSession::ServerSession() {} -ServerSession::~ServerSession() {} +ServerSession::ServerSession() = default; +ServerSession::~ServerSession() = default; ResultVal> ServerSession::Create(std::string name, std::shared_ptr hle_handler) { SharedPtr server_session(new ServerSession); From dd8887c8cfbb6d3010dde240278a3d4018c5dd85 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 5 Dec 2016 11:02:08 -0500 Subject: [PATCH 09/18] KServerPorts now have an HLE handler "template", which is inherited by all ServerSessions created from it. --- src/core/hle/kernel/client_port.cpp | 10 ++++++++- src/core/hle/kernel/client_port.h | 10 +++++---- src/core/hle/kernel/client_session.cpp | 2 +- src/core/hle/kernel/client_session.h | 21 ++++++++++-------- src/core/hle/kernel/server_port.cpp | 3 ++- src/core/hle/kernel/server_port.h | 13 ++++++++++- src/core/hle/kernel/server_session.cpp | 6 +++--- src/core/hle/kernel/server_session.h | 30 +++++++++++++------------- src/core/hle/service/service.cpp | 14 ++++++------ src/core/hle/service/service.h | 14 ++++++++---- src/core/hle/service/srv.cpp | 14 +++--------- src/core/hle/svc.cpp | 18 +++++----------- 12 files changed, 86 insertions(+), 69 deletions(-) diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 5ee7679eb..f25cb48dd 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -13,10 +13,18 @@ namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} -void ClientPort::AddWaitingSession(SharedPtr server_session) { +SharedPtr ClientPort::Connect() { + // Create a new session pair, let the created sessions inherit the parent port's HLE handler. + auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); + auto client_session = std::get>(sessions); + auto server_session = std::get>(sessions); + server_port->pending_sessions.push_back(server_session); + // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); + + return std::move(client_session); } } // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 4848cb4c4..d217c6649 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -11,7 +11,7 @@ namespace Kernel { class ServerPort; -class ServerSession; +class ClientSession; class ClientPort final : public Object { public: @@ -29,15 +29,17 @@ public: } /** - * Adds the specified server session to the queue of pending sessions of the associated ServerPort - * @param server_session Server session to add to the queue + * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's list of pending sessions, + * and signals the ServerPort, causing any threads waiting on it to awake. + * @returns ClientSession The client endpoint of the created Session pair. */ - void AddWaitingSession(SharedPtr server_session); + SharedPtr Connect(); SharedPtr server_port; ///< ServerPort associated with this client port. u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions; ///< Number of currently open sessions to this port std::string name; ///< Name of client port (optional) + private: ClientPort(); ~ClientPort() override; diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index c90fbc69d..6c577610d 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -20,7 +20,7 @@ ResultVal> ClientSession::Create(SharedPtr>(std::move(client_session)); } -ResultCode ClientSession::HandleSyncRequest() { +ResultCode ClientSession::SendSyncRequest() { // Signal the server session that new data is available return server_session->HandleSyncRequest(); } diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index e34528301..45f479901 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -17,17 +17,12 @@ class ServerSession; class ClientSession final : public Object { public: - /** - * Creates a client session. - * @param server_session The server session associated with this client session - * @param name Optional name of client session - * @return The created client session - */ - static ResultVal> Create(SharedPtr server_session, std::string name = "Unknown"); + friend class ServerSession; std::string GetTypeName() const override { return "ClientSession"; } + std::string GetName() const override { return name; } @@ -38,10 +33,10 @@ public: } /** - * Handle a SyncRequest from the emulated application. + * Sends an SyncRequest from the current emulated thread. * @return ResultCode of the operation. */ - ResultCode HandleSyncRequest(); + ResultCode SendSyncRequest(); std::string name; ///< Name of client port (optional) SharedPtr server_session; ///< The server session associated with this client session. @@ -49,6 +44,14 @@ public: private: ClientSession(); ~ClientSession() override; + + /** + * Creates a client session. + * @param server_session The server session associated with this client session + * @param name Optional name of client session + * @return The created client session + */ + static ResultVal> Create(SharedPtr server_session, std::string name = "Unknown"); }; } // namespace diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 8e3ec8a14..f90fe76d5 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -24,12 +24,13 @@ void ServerPort::Acquire() { } std::tuple, SharedPtr> ServerPort::CreatePortPair( - u32 max_sessions, std::string name) { + u32 max_sessions, std::string name, std::shared_ptr hle_handler) { SharedPtr server_port(new ServerPort); SharedPtr client_port(new ClientPort); server_port->name = name + "_Server"; + server_port->hle_handler = hle_handler; client_port->name = name + "_Client"; client_port->server_port = server_port; client_port->max_sessions = max_sessions; diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index fa9448ca0..dee0b1a9a 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -9,6 +9,10 @@ #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +namespace Service { +class SessionRequestHandler; +} + namespace Kernel { class ClientPort; @@ -19,10 +23,13 @@ public: * Creates a pair of ServerPort and an associated ClientPort. * @param max_sessions Maximum number of sessions to the port * @param name Optional name of the ports + * @param hle_handler Optional HLE handler template for the port, + * ServerSessions crated from this port will inherit a reference to this handler. * @return The created port tuple */ static std::tuple, SharedPtr> CreatePortPair( - u32 max_sessions, std::string name = "UnknownPort"); + u32 max_sessions, std::string name = "UnknownPort", + std::shared_ptr hle_handler = nullptr); std::string GetTypeName() const override { return "ServerPort"; @@ -41,6 +48,10 @@ public: std::vector> pending_sessions; ///< ServerSessions waiting to be accepted by the port + /// This session's HLE request handler template (optional) + /// ServerSessions created from this port inherit a reference to this handler. + std::shared_ptr hle_handler; + bool ShouldWait() override; void Acquire() override; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index be334efd7..3782cb493 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -47,10 +47,10 @@ ResultCode ServerSession::HandleSyncRequest() { } std::tuple, SharedPtr> ServerSession::CreateSessionPair(const std::string& name, std::shared_ptr hle_handler) { - auto server_session = ServerSession::Create(name + "Server", hle_handler).MoveFrom(); - auto client_session = ClientSession::Create(server_session, name + "Client").MoveFrom(); + auto server_session = ServerSession::Create(name + "_Server", hle_handler).MoveFrom(); + auto client_session = ClientSession::Create(server_session, name + "_Client").MoveFrom(); - return std::make_tuple(server_session, client_session); + return std::make_tuple(std::move(server_session), std::move(client_session)); } } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 70661e9af..c73ccee73 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -29,20 +29,8 @@ class ClientSession; * the request, the response is marshalled back to the caller's TLS buffer and control is * transferred back to it. */ -class ServerSession : public WaitObject { +class ServerSession final : public WaitObject { public: - ServerSession(); - ~ServerSession() override; - - /** - * Creates a server session. The server session can have an optional HLE handler, - * which will be invoked to handle the IPC requests that this session receives. - * @param name Optional name of the server session. - * @param hle_handler Optional HLE handler for this server session. - * @return The created server session - */ - static ResultVal> Create(std::string name = "Unknown", std::shared_ptr hle_handler = nullptr); - std::string GetTypeName() const override { return "ServerSession"; } @@ -61,10 +49,9 @@ public: /** * Handle a sync request from the emulated application. - * Only HLE services should override this function. * @returns ResultCode from the operation. */ - virtual ResultCode HandleSyncRequest(); + ResultCode HandleSyncRequest(); bool ShouldWait() override; @@ -73,5 +60,18 @@ public: std::string name; ///< The name of this session (optional) bool signaled; ///< Whether there's new data available to this ServerSession std::shared_ptr hle_handler; ///< This session's HLE request handler (optional) + +private: + ServerSession(); + ~ServerSession() override; + + /** + * Creates a server session. The server session can have an optional HLE handler, + * which will be invoked to handle the IPC requests that this session receives. + * @param name Optional name of the server session. + * @param hle_handler Optional HLE handler for this server session. + * @return The created server session + */ + static ResultVal> Create(std::string name = "Unknown", std::shared_ptr hle_handler = nullptr); }; } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index c90802455..3462af8ce 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -44,8 +44,8 @@ namespace Service { -std::unordered_map, std::shared_ptr>> g_kernel_named_ports; -std::unordered_map, std::shared_ptr>> g_srv_services; +std::unordered_map> g_kernel_named_ports; +std::unordered_map> g_srv_services; /** * Creates a function string for logging, complete with the name (or header code, depending @@ -102,15 +102,17 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); + auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr(interface_)); auto client_port = std::get>(ports); - g_kernel_named_ports.emplace(interface_->GetPortName(), std::make_tuple(client_port, std::shared_ptr(interface_))); + g_kernel_named_ports.emplace(interface_->GetPortName(), client_port); } void AddService(Interface* interface_) { - auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); + auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr(interface_)); auto client_port = std::get>(ports); - g_srv_services.emplace(interface_->GetPortName(), std::make_tuple(client_port, std::shared_ptr(interface_))); + g_srv_services.emplace(interface_->GetPortName(), client_port); } /// Initialize ServiceManager diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 931512339..e85882713 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -176,7 +176,11 @@ namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE port -/// TODO(Subv): Write documentation for this class +/** + * Interface implemented by HLE Session handlers. + * This can be provided to a ServerSession in order to hook into several relevant events (such as a new connection or a SyncRequest) + * so they can be implemented in the emulator. + */ class SessionRequestHandler { public: /** @@ -190,7 +194,9 @@ public: virtual ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) = 0; }; -/// Interface to a CTROS service +/** + * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a table mapping header ids to handler functions. + */ class Interface : public SessionRequestHandler { public: std::string GetName() const { @@ -257,9 +263,9 @@ void Init(); void Shutdown(); /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. -extern std::unordered_map, std::shared_ptr>> g_kernel_named_ports; +extern std::unordered_map> g_kernel_named_ports; /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. -extern std::unordered_map, std::shared_ptr>> g_srv_services; +extern std::unordered_map> g_srv_services; /// Adds a service to the services table void AddService(Interface* interface_); diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index c0abfd711..bb2c8fcc4 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -85,21 +85,13 @@ static void GetServiceHandle(Service::Interface* self) { auto it = Service::g_srv_services.find(port_name); if (it != Service::g_srv_services.end()) { - auto client_port = std::get>(it->second); - // The hle_handler will be nullptr if this port was registered by the emulated - // application by means of srv:RegisterService. - auto hle_handler = std::get>(it->second); - - // Create a new session pair - auto sessions = Kernel::ServerSession::CreateSessionPair(port_name, hle_handler); - auto client_session = std::get>(sessions); - auto server_session = std::get>(sessions); + auto client_port = it->second; // Note: Threads do not wait for the server endpoint to call // AcceptSession before returning from this call. - // Add the server session to the port's queue - client_port->AddWaitingSession(server_session); + // Connect to the port and retrieve the client endpoint of the connection Session. + auto client_session = client_port->Connect(); // Return the client session cmd_buff[3] = Kernel::g_handle_table.Create(client_session).MoveFrom(); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index ab0eb9d86..4189d75ac 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -224,18 +224,10 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { return ERR_NOT_FOUND; } - auto client_port = std::get>(it->second); - // The hle_handler will be nullptr if this port was registered by the emulated - // application by means of svcCreatePort with a defined name. - auto hle_handler = std::get>(it->second); + auto client_port = it->second; - // Create a new session pair - auto sessions = Kernel::ServerSession::CreateSessionPair(port_name, hle_handler); - auto client_session = std::get>(sessions); - auto server_session = std::get>(sessions); - - // Add the server session to the port's queue - client_port->AddWaitingSession(server_session); + // Connect to the port and retrieve the client endpoint of the connection Session. + auto client_session = client_port->Connect(); // Note: Threads do not wait for the server endpoint to call // AcceptSession before returning from this call. @@ -254,8 +246,8 @@ static ResultCode SendSyncRequest(Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); - // TODO(Subv): Wait the current thread and reschedule if this request is not going to be handled by HLE code. - return session->HandleSyncRequest(); + // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server responds and cause a reschedule. + return session->SendSyncRequest(); } /// Close a handle From 29d809b6e164ea19c58557e6958fe011e062dff3 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 5 Dec 2016 11:13:22 -0500 Subject: [PATCH 10/18] Kernel: Remove the Redirection handle type. --- src/core/hle/kernel/kernel.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 9808d375b..0b811c5a7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -35,7 +35,6 @@ enum class HandleType : u32 { Event, Mutex, SharedMemory, - Redirection, Thread, Process, AddressArbiter, @@ -93,7 +92,6 @@ public: case HandleType::Unknown: case HandleType::SharedMemory: - case HandleType::Redirection: case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: From 00f0c775702af4145a4a81ec5d357c3586a5c6c3 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 5 Dec 2016 12:05:00 -0500 Subject: [PATCH 11/18] Split SessionRequestHandler::HandleSyncRequest into HandleSyncRequest, TranslateRequest and HandleSyncRequestImpl. HandleSyncRequest now takes care of calling the command buffer translate function before actually invoking the command handler for HLE services. --- src/core/hle/kernel/client_port.cpp | 1 + src/core/hle/kernel/server_port.h | 1 + src/core/hle/service/fs/archive.cpp | 14 ++++++-------- src/core/hle/service/fs/archive.h | 10 ++++++---- src/core/hle/service/service.cpp | 27 +++++++++++++++++++++++---- src/core/hle/service/service.h | 28 ++++++++++++++++++++++------ 6 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index f25cb48dd..b6a4cab26 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -4,6 +4,7 @@ #include "common/assert.h" #include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index dee0b1a9a..b0f8df62c 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include "common/common_types.h" diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index a9f457726..c10d6a3a9 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -93,7 +93,7 @@ File::File(std::unique_ptr&& backend, const FileSys::Path& File::~File() {} -ResultCode File::HandleSyncRequest(Kernel::SharedPtr server_session) { +void File::HandleSyncRequestImpl(Kernel::SharedPtr server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { @@ -116,7 +116,7 @@ ResultCode File::HandleSyncRequest(Kernel::SharedPtr serv ResultVal read = backend->Read(offset, data.size(), data.data()); if (read.Failed()) { cmd_buff[1] = read.Code().raw; - return read.Code(); + return; } Memory::WriteBlock(address, data.data(), *read); cmd_buff[2] = static_cast(*read); @@ -137,7 +137,7 @@ ResultCode File::HandleSyncRequest(Kernel::SharedPtr serv ResultVal written = backend->Write(offset, data.size(), flush != 0, data.data()); if (written.Failed()) { cmd_buff[1] = written.Code().raw; - return written.Code(); + return; } cmd_buff[2] = static_cast(*written); break; @@ -195,10 +195,9 @@ ResultCode File::HandleSyncRequest(Kernel::SharedPtr serv LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return error; + return; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return RESULT_SUCCESS; } Directory::Directory(std::unique_ptr&& backend, @@ -207,7 +206,7 @@ Directory::Directory(std::unique_ptr&& backend, Directory::~Directory() {} -ResultCode Directory::HandleSyncRequest(Kernel::SharedPtr server_session) { +void Directory::HandleSyncRequestImpl(Kernel::SharedPtr server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); DirectoryCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { @@ -237,10 +236,9 @@ ResultCode Directory::HandleSyncRequest(Kernel::SharedPtr LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); ResultCode error = UnimplementedFunction(ErrorModule::FS); cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return RESULT_SUCCESS; + return; } cmd_buff[1] = RESULT_SUCCESS.raw; // No error - return RESULT_SUCCESS; } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 29527ef48..cb014b5d7 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -50,11 +50,12 @@ public: return "Path: " + path.DebugStr(); } - ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) override; - FileSys::Path path; ///< Path of the file u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means std::unique_ptr backend; ///< File backend interface + +protected: + void HandleSyncRequestImpl(Kernel::SharedPtr server_session) override; }; class Directory : public SessionRequestHandler { @@ -66,10 +67,11 @@ public: return "Directory: " + path.DebugStr(); } - ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) override; - FileSys::Path path; ///< Path of the directory std::unique_ptr backend; ///< File backend interface + +protected: + void HandleSyncRequestImpl(Kernel::SharedPtr server_session) override; }; /** diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 3462af8ce..3d5e3058c 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -64,7 +64,27 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -ResultCode Interface::HandleSyncRequest(Kernel::SharedPtr server_session) { +ResultCode SessionRequestHandler::HandleSyncRequest(Kernel::SharedPtr server_session) { + // Attempt to translate the incoming request's command buffer. + ResultCode result = TranslateRequest(server_session); + + if (result.IsError()) + return result; + + // Actually handle the request + HandleSyncRequestImpl(server_session); + + // TODO(Subv): Translate the response command buffer. + + return RESULT_SUCCESS; +} + +ResultCode SessionRequestHandler::TranslateRequest(Kernel::SharedPtr server_session) { + // TODO(Subv): Implement this function once multiple concurrent processes are supported. + return RESULT_SUCCESS; +} + +void Interface::HandleSyncRequestImpl(Kernel::SharedPtr server_session) { // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which session triggered each command. u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -80,14 +100,12 @@ ResultCode Interface::HandleSyncRequest(Kernel::SharedPtr // TODO(bunnei): Hack - ignore error cmd_buff[1] = 0; - return RESULT_SUCCESS; + return; } LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); itr->second.func(this); - - return RESULT_SUCCESS; // TODO: Implement return from actual function, it should fail if the parameter translation fails } void Interface::Register(const FunctionInfo* functions, size_t n) { @@ -179,4 +197,5 @@ void Shutdown() { 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 e85882713..7b7db8499 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -187,11 +187,27 @@ public: * Dispatches and handles a sync request from the emulated application. * @param server_session The ServerSession that was triggered for this sync request, * it should be used to differentiate which client (As in ClientSession) we're answering to. - * TODO(Subv): Make a HandleSyncRequestParent function that is called from the outside and does { ReturnIfError(Translate()); HandleSyncRequest(); } - * The Translate() function would copy the command buffer from the ServerSession thread's TLS into a temporary buffer, and pass it to HandleSyncRequest. - * TODO(Subv): HandleSyncRequest's return type should be void. + * @returns ResultCode the result code of the translate operation. */ - virtual ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) = 0; + ResultCode HandleSyncRequest(Kernel::SharedPtr server_session); + +protected: + /** + * Handles a sync request from the emulated application and writes the response to the command buffer. + * TODO(Subv): Use a wrapper structure to hold all the information relevant to + * this request (ServerSession, Originator thread, Translated command buffer, etc). + */ + virtual void HandleSyncRequestImpl(Kernel::SharedPtr server_session) = 0; + +private: + /** + * Performs command buffer translation for this request. + * The command buffer from the ServerSession thread's TLS is copied into a + * buffer and all descriptors in the buffer are processed. + * TODO(Subv): Implement this function, currently we do not support multiple processes running at once, + * but once that is implemented we'll need to properly translate all descriptors in the command buffer. + */ + ResultCode TranslateRequest(Kernel::SharedPtr server_session); }; /** @@ -231,9 +247,9 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultCode HandleSyncRequest(Kernel::SharedPtr server_session) override; - protected: + void HandleSyncRequestImpl(Kernel::SharedPtr server_session) override; + /** * Registers the functions in the service */ From 61a2fe8c3bcd5e6dc7e97945b923d1a5bd8099ec Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 5 Dec 2016 13:44:41 -0500 Subject: [PATCH 12/18] HLE: Use a member variable instead of a virtual function to retrieve the max number of sessions that can be connected to an HLE service at the same time. --- src/core/hle/service/apt/apt.h | 2 ++ src/core/hle/service/apt/apt_a.cpp | 2 +- src/core/hle/service/apt/apt_s.cpp | 2 +- src/core/hle/service/apt/apt_u.cpp | 2 +- src/core/hle/service/service.h | 18 +++++++++++++----- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 44dbd8757..9bc6327ed 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -14,6 +14,8 @@ class Interface; namespace APT { +static const u32 MaxAPTSessions = 2; ///< Each APT service can only have up to 2 sessions connected at the same time. + /// Holds information about the parameters used in Send/Glance/ReceiveParameter struct MessageParameter { u32 sender_id = 0; diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index a7a0c8a41..7f37a7f54 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -39,7 +39,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x01020000, CheckNew3DS, "CheckNew3DS"}, }; -APT_A_Interface::APT_A_Interface() { +APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index c4556a5de..933f26e60 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x01020000, CheckNew3DS, "CheckNew3DS"}, }; -APT_S_Interface::APT_S_Interface() { +APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index a731c39f6..e06084a1e 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x01020000, CheckNew3DS, "CheckNew3DS"}, }; -APT_U_Interface::APT_U_Interface() { +APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) { Register(FunctionTable); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 7b7db8499..2274e50ca 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -174,7 +174,7 @@ inline DescriptorType GetDescriptorType(u32 descriptor) { namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) -static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE port +static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE service /** * Interface implemented by HLE Session handlers. @@ -215,6 +215,15 @@ private: */ class Interface : public SessionRequestHandler { public: + /** + * Creates an HLE interface with the specified max sessions. + * @param max_sessions Maximum number of sessions that can be + * connected to this service at the same time. + */ + Interface(u32 max_sessions = DefaultMaxSessions) : max_sessions(max_sessions) { } + + virtual ~Interface() = default; + std::string GetName() const { return GetPortName(); } @@ -222,14 +231,12 @@ public: virtual void SetVersion(u32 raw_version) { version.raw = raw_version; } - virtual ~Interface() {} /** - * Gets the maximum allowed number of sessions that can be connected to this port at the same time. - * It should be overwritten by each service implementation for more fine-grained control. + * Gets the maximum allowed number of sessions that can be connected to this service at the same time. * @returns The maximum number of connections allowed. */ - virtual u32 GetMaxSessions() const { return DefaultMaxSessions; } + u32 GetMaxSessions() const { return max_sessions; } typedef void (*Function)(Interface*); @@ -269,6 +276,7 @@ protected: } version = {}; private: + u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle. boost::container::flat_map m_functions; }; From c93c5a72bb46796e898f54a7c13dfb8d941ddd4d Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 5 Dec 2016 13:59:57 -0500 Subject: [PATCH 13/18] Return an error code when connecting to a saturated port. The error code was taken from the 3DS kernel. --- src/core/hle/kernel/client_port.cpp | 11 +++++++++-- src/core/hle/kernel/client_port.h | 4 ++-- src/core/hle/result.h | 1 + src/core/hle/service/srv.cpp | 8 ++++++-- src/core/hle/svc.cpp | 3 ++- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index b6a4cab26..120ce554d 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -14,7 +14,14 @@ namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} -SharedPtr ClientPort::Connect() { +ResultVal> ClientPort::Connect() { + if (active_sessions >= max_sessions) { + return ResultCode(ErrorDescription::MaxConnectionsReached, + ErrorModule::OS, ErrorSummary::WouldBlock, + ErrorLevel::Temporary); + } + active_sessions++; + // Create a new session pair, let the created sessions inherit the parent port's HLE handler. auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); auto client_session = std::get>(sessions); @@ -25,7 +32,7 @@ SharedPtr ClientPort::Connect() { // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); - return std::move(client_session); + return MakeResult>(std::move(client_session)); } } // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index d217c6649..0039cf028 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -31,9 +31,9 @@ public: /** * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's list of pending sessions, * and signals the ServerPort, causing any threads waiting on it to awake. - * @returns ClientSession The client endpoint of the created Session pair. + * @returns ClientSession The client endpoint of the created Session pair, or error code. */ - SharedPtr Connect(); + ResultVal> Connect(); SharedPtr server_port; ///< ServerPort associated with this client port. u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have diff --git a/src/core/hle/result.h b/src/core/hle/result.h index f7356f9d8..20562aed6 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -18,6 +18,7 @@ enum class ErrorDescription : u32 { Success = 0, WrongPermission = 46, OS_InvalidBufferDescriptor = 48, + MaxConnectionsReached = 52, WrongAddress = 53, FS_ArchiveNotMounted = 101, FS_FileNotFound = 112, diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index bb2c8fcc4..ff7a84347 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -93,8 +93,12 @@ static void GetServiceHandle(Service::Interface* self) { // Connect to the port and retrieve the client endpoint of the connection Session. auto client_session = client_port->Connect(); - // Return the client session - cmd_buff[3] = Kernel::g_handle_table.Create(client_session).MoveFrom(); + res = client_session.Code(); + + 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]); } else { LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 4189d75ac..0a2b474ee 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -227,7 +227,8 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { auto client_port = it->second; // Connect to the port and retrieve the client endpoint of the connection Session. - auto client_session = client_port->Connect(); + SharedPtr client_session; + CASCADE_RESULT(client_session, client_port->Connect()); // Note: Threads do not wait for the server endpoint to call // AcceptSession before returning from this call. From f9bcf895103e5a6d99f5fe755bcac92b7781fd38 Mon Sep 17 00:00:00 2001 From: Subv Date: Thu, 8 Dec 2016 11:06:19 -0500 Subject: [PATCH 14/18] Use std::move where appropriate. --- src/core/CMakeLists.txt | 1 + src/core/hle/ipc.h | 162 +++++++++++++++++++++++++ src/core/hle/kernel/client_port.cpp | 5 +- src/core/hle/kernel/client_session.cpp | 2 +- src/core/hle/kernel/server_port.cpp | 2 +- src/core/hle/kernel/server_session.cpp | 7 +- src/core/hle/kernel/server_session.h | 4 +- src/core/hle/service/fs/archive.h | 4 +- src/core/hle/service/service.cpp | 7 +- src/core/hle/service/service.h | 159 +----------------------- src/core/hle/service/srv.cpp | 5 - src/core/hle/svc.cpp | 6 +- 12 files changed, 187 insertions(+), 177 deletions(-) create mode 100644 src/core/hle/ipc.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 59260d2e8..5d2537202 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -179,6 +179,7 @@ set(HEADERS hle/config_mem.h hle/function_wrappers.h hle/hle.h + hle/ipc.h hle/applets/applet.h hle/applets/erreula.h hle/applets/mii_selector.h diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h new file mode 100644 index 000000000..90ea4d191 --- /dev/null +++ b/src/core/hle/ipc.h @@ -0,0 +1,162 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "core/hle/kernel/thread.h" +#include "core/memory.h" + +namespace Kernel { +class ServerSession; + +// TODO(Subv): Move these declarations out of here +static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header + +/** + * Returns a pointer to the command buffer in the current thread's TLS + * TODO(Subv): This is not entirely correct, the command buffer should be copied from + * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to + * the service handler process' memory. + * @param offset Optional offset into command buffer + * @return Pointer to command buffer + */ +inline u32* GetCommandBuffer(const int offset = 0) { + return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + + offset); +} +} + +namespace IPC { + +enum DescriptorType : u32 { + // Buffer related desciptors types (mask : 0x0F) + StaticBuffer = 0x02, + PXIBuffer = 0x04, + MappedBuffer = 0x08, + // Handle related descriptors types (mask : 0x30, but need to check for buffer related + // descriptors first ) + CopyHandle = 0x00, + MoveHandle = 0x10, + CallingPid = 0x20, +}; + +/** + * @brief Creates a command header to be used for IPC + * @param command_id ID of the command to create a header for. + * @param normal_params Size of the normal parameters in words. Up to 63. + * @param translate_params_size Size of the translate parameters in words. Up to 63. + * @return The created IPC header. + * + * Normal parameters are sent directly to the process while the translate parameters might go + * through modifications and checks by the kernel. + * The translate parameters are described by headers generated with the IPC::*Desc functions. + * + * @note While #normal_params is equivalent to the number of normal parameters, + * #translate_params_size includes the size occupied by the translate parameters headers. + */ +constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, + unsigned int translate_params_size) { + return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | + (u32(translate_params_size) & 0x3F); +} + +union Header { + u32 raw; + BitField<0, 6, u32> translate_params_size; + BitField<6, 6, u32> normal_params; + BitField<16, 16, u32> command_id; +}; + +inline Header ParseHeader(u32 header) { + return {header}; +} + +constexpr u32 MoveHandleDesc(u32 num_handles = 1) { + return MoveHandle | ((num_handles - 1) << 26); +} + +constexpr u32 CopyHandleDesc(u32 num_handles = 1) { + return CopyHandle | ((num_handles - 1) << 26); +} + +constexpr u32 CallingPidDesc() { + return CallingPid; +} + +constexpr bool isHandleDescriptor(u32 descriptor) { + return (descriptor & 0xF) == 0x0; +} + +constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) { + return (handle_descriptor >> 26) + 1; +} + +constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) { + return StaticBuffer | (size << 14) | ((buffer_id & 0xF) << 10); +} + +union StaticBufferDescInfo { + u32 raw; + BitField<10, 4, u32> buffer_id; + BitField<14, 18, u32> size; +}; + +inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { + return {desc}; +} + +/** + * @brief Creates a header describing a buffer to be sent over PXI. + * @param size Size of the buffer. Max 0x00FFFFFF. + * @param buffer_id The Id of the buffer. Max 0xF. + * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have + * read-write access. + * @return The created PXI buffer header. + * + * The next value is a phys-address of a table located in the BASE memregion. + */ +inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { + u32 type = PXIBuffer; + if (is_read_only) + type |= 0x2; + return type | (size << 8) | ((buffer_id & 0xF) << 4); +} + +enum MappedBufferPermissions { + R = 1, + W = 2, + RW = R | W, +}; + +constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { + return MappedBuffer | (size << 4) | (u32(perms) << 1); +} + +union MappedBufferDescInfo { + u32 raw; + BitField<4, 28, u32> size; + BitField<1, 2, MappedBufferPermissions> perms; +}; + +inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { + return{ desc }; +} + +inline DescriptorType GetDescriptorType(u32 descriptor) { + // Note: Those checks must be done in this order + if (isHandleDescriptor(descriptor)) + return (DescriptorType)(descriptor & 0x30); + + // handle the fact that the following descriptors can have rights + if (descriptor & MappedBuffer) + return MappedBuffer; + + if (descriptor & PXIBuffer) + return PXIBuffer; + + return StaticBuffer; +} + +} // namespace IPC diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 120ce554d..20179e546 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -15,6 +15,9 @@ ClientPort::ClientPort() {} ClientPort::~ClientPort() {} ResultVal> ClientPort::Connect() { + // Note: Threads do not wait for the server endpoint to call + // AcceptSession before returning from this call. + if (active_sessions >= max_sessions) { return ResultCode(ErrorDescription::MaxConnectionsReached, ErrorModule::OS, ErrorSummary::WouldBlock, @@ -27,7 +30,7 @@ ResultVal> ClientPort::Connect() { auto client_session = std::get>(sessions); auto server_session = std::get>(sessions); - server_port->pending_sessions.push_back(server_session); + server_port->pending_sessions.push_back(std::move(server_session)); // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 6c577610d..30ef10764 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -16,7 +16,7 @@ ResultVal> ClientSession::Create(SharedPtr client_session(new ClientSession); client_session->name = std::move(name); - client_session->server_session = server_session; + client_session->server_session = std::move(server_session); return MakeResult>(std::move(client_session)); } diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index f90fe76d5..f7699f023 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -30,7 +30,7 @@ std::tuple, SharedPtr> ServerPort::CreatePortP SharedPtr client_port(new ClientPort); server_port->name = name + "_Server"; - server_port->hle_handler = hle_handler; + server_port->hle_handler = std::move(hle_handler); client_port->name = name + "_Client"; client_port->server_port = server_port; client_port->max_sessions = max_sessions; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 3782cb493..f8bccadfd 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -18,7 +18,7 @@ ResultVal> ServerSession::Create(std::string name, std: server_session->name = std::move(name); server_session->signaled = false; - server_session->hle_handler = hle_handler; + server_session->hle_handler = std::move(hle_handler); return MakeResult>(std::move(server_session)); } @@ -46,8 +46,9 @@ ResultCode ServerSession::HandleSyncRequest() { return RESULT_SUCCESS; } -std::tuple, SharedPtr> ServerSession::CreateSessionPair(const std::string& name, std::shared_ptr hle_handler) { - auto server_session = ServerSession::Create(name + "_Server", hle_handler).MoveFrom(); +ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name, + std::shared_ptr hle_handler) { + auto server_session = ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); auto client_session = ClientSession::Create(server_session, name + "_Client").MoveFrom(); return std::make_tuple(std::move(server_session), std::move(client_session)); diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index c73ccee73..7f00db07b 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -40,12 +40,14 @@ public: return HANDLE_TYPE; } + using SessionPair = std::tuple, SharedPtr>; + /** * Creates a pair of ServerSession and an associated ClientSession. * @param name Optional name of the ports * @return The created session tuple */ - static std::tuple, SharedPtr> CreateSessionPair(const std::string& name = "Unknown", std::shared_ptr hle_handler = nullptr); + static SessionPair CreateSessionPair(const std::string& name = "Unknown", std::shared_ptr hle_handler = nullptr); /** * Handle a sync request from the emulated application. diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index cb014b5d7..09a922fb5 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -41,7 +41,7 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1 }; typedef u64 ArchiveHandle; -class File : public SessionRequestHandler, public std::enable_shared_from_this { +class File final : public SessionRequestHandler, public std::enable_shared_from_this { public: File(std::unique_ptr&& backend, const FileSys::Path& path); ~File(); @@ -58,7 +58,7 @@ protected: void HandleSyncRequestImpl(Kernel::SharedPtr server_session) override; }; -class Directory : public SessionRequestHandler { +class Directory final : public SessionRequestHandler { public: Directory(std::unique_ptr&& backend, const FileSys::Path& path); ~Directory(); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 3d5e3058c..6ea5cf745 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -84,6 +84,9 @@ ResultCode SessionRequestHandler::TranslateRequest(Kernel::SharedPtr server_session) { // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which session triggered each command. @@ -123,14 +126,14 @@ static void AddNamedPort(Interface* interface_) { auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), std::shared_ptr(interface_)); auto client_port = std::get>(ports); - g_kernel_named_ports.emplace(interface_->GetPortName(), client_port); + g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); } void AddService(Interface* interface_) { auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), std::shared_ptr(interface_)); auto client_port = std::get>(ports); - g_srv_services.emplace(interface_->GetPortName(), client_port); + g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); } /// Initialize ServiceManager diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 2274e50ca..ba5ba062e 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -9,165 +9,12 @@ #include #include #include "common/common_types.h" +#include "core/hle/ipc.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/thread.h" #include "core/hle/result.h" #include "core/memory.h" -namespace Kernel { -class ServerSession; - -// TODO(Subv): Move these declarations out of here -static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header - -/** - * Returns a pointer to the command buffer in the current thread's TLS - * TODO(Subv): This is not entirely correct, the command buffer should be copied from - * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to - * the service handler process' memory. - * @param offset Optional offset into command buffer - * @return Pointer to command buffer - */ -inline u32* GetCommandBuffer(const int offset = 0) { - return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + - offset); -} -} - -// TODO(Subv): Move this namespace out of here -namespace IPC { - -enum DescriptorType : u32 { - // Buffer related desciptors types (mask : 0x0F) - StaticBuffer = 0x02, - PXIBuffer = 0x04, - MappedBuffer = 0x08, - // Handle related descriptors types (mask : 0x30, but need to check for buffer related - // descriptors first ) - CopyHandle = 0x00, - MoveHandle = 0x10, - CallingPid = 0x20, -}; - -/** - * @brief Creates a command header to be used for IPC - * @param command_id ID of the command to create a header for. - * @param normal_params Size of the normal parameters in words. Up to 63. - * @param translate_params_size Size of the translate parameters in words. Up to 63. - * @return The created IPC header. - * - * Normal parameters are sent directly to the process while the translate parameters might go - * through modifications and checks by the kernel. - * The translate parameters are described by headers generated with the IPC::*Desc functions. - * - * @note While #normal_params is equivalent to the number of normal parameters, - * #translate_params_size includes the size occupied by the translate parameters headers. - */ -constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, - unsigned int translate_params_size) { - return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | - (u32(translate_params_size) & 0x3F); -} - -union Header { - u32 raw; - BitField<0, 6, u32> translate_params_size; - BitField<6, 6, u32> normal_params; - BitField<16, 16, u32> command_id; -}; - -inline Header ParseHeader(u32 header) { - return {header}; -} - -constexpr u32 MoveHandleDesc(u32 num_handles = 1) { - return MoveHandle | ((num_handles - 1) << 26); -} - -constexpr u32 CopyHandleDesc(u32 num_handles = 1) { - return CopyHandle | ((num_handles - 1) << 26); -} - -constexpr u32 CallingPidDesc() { - return CallingPid; -} - -constexpr bool isHandleDescriptor(u32 descriptor) { - return (descriptor & 0xF) == 0x0; -} - -constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) { - return (handle_descriptor >> 26) + 1; -} - -constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) { - return StaticBuffer | (size << 14) | ((buffer_id & 0xF) << 10); -} - -union StaticBufferDescInfo { - u32 raw; - BitField<10, 4, u32> buffer_id; - BitField<14, 18, u32> size; -}; - -inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { - return {desc}; -} - -/** - * @brief Creates a header describing a buffer to be sent over PXI. - * @param size Size of the buffer. Max 0x00FFFFFF. - * @param buffer_id The Id of the buffer. Max 0xF. - * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have - * read-write access. - * @return The created PXI buffer header. - * - * The next value is a phys-address of a table located in the BASE memregion. - */ -inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { - u32 type = PXIBuffer; - if (is_read_only) - type |= 0x2; - return type | (size << 8) | ((buffer_id & 0xF) << 4); -} - -enum MappedBufferPermissions { - R = 1, - W = 2, - RW = R | W, -}; - -constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { - return MappedBuffer | (size << 4) | (u32(perms) << 1); -} - -union MappedBufferDescInfo { - u32 raw; - BitField<4, 28, u32> size; - BitField<1, 2, MappedBufferPermissions> perms; -}; - -inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { - return{ desc }; -} - -inline DescriptorType GetDescriptorType(u32 descriptor) { - // Note: Those checks must be done in this order - if (isHandleDescriptor(descriptor)) - return (DescriptorType)(descriptor & 0x30); - - // handle the fact that the following descriptors can have rights - if (descriptor & MappedBuffer) - return MappedBuffer; - - if (descriptor & PXIBuffer) - return PXIBuffer; - - return StaticBuffer; -} - -} // namespace IPC - //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service @@ -220,9 +67,9 @@ public: * @param max_sessions Maximum number of sessions that can be * connected to this service at the same time. */ - Interface(u32 max_sessions = DefaultMaxSessions) : max_sessions(max_sessions) { } + Interface(u32 max_sessions = DefaultMaxSessions); - virtual ~Interface() = default; + virtual ~Interface(); std::string GetName() const { return GetPortName(); diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index ff7a84347..37420201b 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -87,12 +87,7 @@ static void GetServiceHandle(Service::Interface* self) { if (it != Service::g_srv_services.end()) { auto client_port = it->second; - // Note: Threads do not wait for the server endpoint to call - // AcceptSession before returning from this call. - - // Connect to the port and retrieve the client endpoint of the connection Session. auto client_session = client_port->Connect(); - res = client_session.Code(); if (client_session.Succeeded()) { diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 0a2b474ee..f24b5c91a 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -226,19 +226,15 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { auto client_port = it->second; - // Connect to the port and retrieve the client endpoint of the connection Session. SharedPtr client_session; CASCADE_RESULT(client_session, client_port->Connect()); - // Note: Threads do not wait for the server endpoint to call - // AcceptSession before returning from this call. - // Return the client session CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session)); return RESULT_SUCCESS; } -/// Synchronize to an OS service +/// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Handle handle) { SharedPtr session = Kernel::g_handle_table.Get(handle); if (session == nullptr) { From 386112da3265d111595329508b860800e5cf14e8 Mon Sep 17 00:00:00 2001 From: Subv Date: Thu, 8 Dec 2016 15:01:10 -0500 Subject: [PATCH 15/18] Added a framework for partially handling Session disconnections. Further implementation will happen in a future commit. Fixes a regression. --- src/core/hle/kernel/client_port.cpp | 8 ++++++-- src/core/hle/kernel/client_session.cpp | 15 ++++++++++++--- src/core/hle/kernel/client_session.h | 11 +++++++++-- src/core/hle/kernel/server_session.cpp | 10 ++++++++-- src/core/hle/service/fs/archive.cpp | 1 + src/core/hle/service/fs/fs_user.cpp | 3 +++ src/core/hle/service/service.cpp | 10 ++++++++++ src/core/hle/service/service.h | 18 ++++++++++++++++++ 8 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 20179e546..bd8ef055d 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -19,9 +19,10 @@ ResultVal> ClientPort::Connect() { // AcceptSession before returning from this call. if (active_sessions >= max_sessions) { - return ResultCode(ErrorDescription::MaxConnectionsReached, + // TODO(Subv): Return an error code in this situation after session disconnection is implemented. + /*return ResultCode(ErrorDescription::MaxConnectionsReached, ErrorModule::OS, ErrorSummary::WouldBlock, - ErrorLevel::Temporary); + ErrorLevel::Temporary);*/ } active_sessions++; @@ -30,6 +31,9 @@ ResultVal> ClientPort::Connect() { auto client_session = std::get>(sessions); auto server_session = std::get>(sessions); + if (server_port->hle_handler) + server_port->hle_handler->ClientConnected(server_session); + server_port->pending_sessions.push_back(std::move(server_session)); // Wake the threads waiting on the ServerPort diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 30ef10764..17302baca 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -10,13 +10,22 @@ namespace Kernel { ClientSession::ClientSession() = default; -ClientSession::~ClientSession() = default; +ClientSession::~ClientSession() { + // This destructor will be called automatically when the last ClientSession handle is closed by the emulated application. -ResultVal> ClientSession::Create(SharedPtr server_session, std::string name) { + if (server_session->hle_handler) + server_session->hle_handler->ClientDisconnected(server_session); + + // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client), + // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to 0xC920181A. +} + +ResultVal> ClientSession::Create(ServerSession* server_session, std::string name) { SharedPtr client_session(new ClientSession); client_session->name = std::move(name); - client_session->server_session = std::move(server_session); + client_session->server_session = server_session; + client_session->session_status = SessionStatus::Open; return MakeResult>(std::move(client_session)); } diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 45f479901..fedbd0625 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -15,6 +15,12 @@ namespace Kernel { class ServerSession; +enum class SessionStatus { + Open = 1, + ClosedByClient = 2, + ClosedBYServer = 3, +}; + class ClientSession final : public Object { public: friend class ServerSession; @@ -39,7 +45,8 @@ public: ResultCode SendSyncRequest(); std::string name; ///< Name of client port (optional) - SharedPtr server_session; ///< The server session associated with this client session. + ServerSession* server_session; ///< The server session associated with this client session. + SessionStatus session_status; ///< The session's current status. private: ClientSession(); @@ -51,7 +58,7 @@ private: * @param name Optional name of client session * @return The created client session */ - static ResultVal> Create(SharedPtr server_session, std::string name = "Unknown"); + static ResultVal> Create(ServerSession* server_session, std::string name = "Unknown"); }; } // namespace diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index f8bccadfd..3fac6b934 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -11,7 +11,11 @@ namespace Kernel { ServerSession::ServerSession() = default; -ServerSession::~ServerSession() = default; +ServerSession::~ServerSession() { + // This destructor will be called automatically when the last ServerSession handle is closed by the emulated application. + // TODO(Subv): Reduce the ClientPort's connection count, + // if the session is still open, set the connection status to 3 (Closed by server), +} ResultVal> ServerSession::Create(std::string name, std::shared_ptr hle_handler) { SharedPtr server_session(new ServerSession); @@ -49,7 +53,9 @@ ResultCode ServerSession::HandleSyncRequest() { ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name, std::shared_ptr hle_handler) { auto server_session = ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); - auto client_session = ClientSession::Create(server_session, name + "_Client").MoveFrom(); + // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want to prevent the + // ServerSession's destructor from being called when the emulated application closes the last ServerSession handle. + auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom(); return std::make_tuple(std::move(server_session), std::move(client_session)); } diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index c10d6a3a9..b63c6eaac 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -174,6 +174,7 @@ void File::HandleSyncRequestImpl(Kernel::SharedPtr server case FileCommand::OpenLinkFile: { LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); + ClientConnected(std::get>(sessions)); cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).ValueOr(INVALID_HANDLE); break; } diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index a29bce22a..ea1050fb6 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -73,6 +73,7 @@ static void OpenFile(Service::Interface* self) { if (file_res.Succeeded()) { std::shared_ptr file = *file_res; auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + file->ClientConnected(std::get>(sessions)); cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { cmd_buff[3] = 0; @@ -135,6 +136,7 @@ static void OpenFileDirectly(Service::Interface* self) { if (file_res.Succeeded()) { std::shared_ptr file = *file_res; auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); + file->ClientConnected(std::get>(sessions)); cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { cmd_buff[3] = 0; @@ -398,6 +400,7 @@ static void OpenDirectory(Service::Interface* self) { if (dir_res.Succeeded()) { std::shared_ptr directory = *dir_res; auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); + directory->ClientConnected(std::get>(sessions)); cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 6ea5cf745..167cb09a8 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + #include "common/logging/log.h" #include "common/string_util.h" @@ -79,6 +81,14 @@ ResultCode SessionRequestHandler::HandleSyncRequest(Kernel::SharedPtr server_session) { + connected_sessions.push_back(server_session); +} + +void SessionRequestHandler::ClientDisconnected(Kernel::SharedPtr server_session) { + boost::range::remove_erase(connected_sessions, server_session); +} + ResultCode SessionRequestHandler::TranslateRequest(Kernel::SharedPtr server_session) { // TODO(Subv): Implement this function once multiple concurrent processes are supported. return RESULT_SUCCESS; diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index ba5ba062e..2293b473a 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -38,6 +38,20 @@ public: */ ResultCode HandleSyncRequest(Kernel::SharedPtr server_session); + /** + * 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 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 server_session); + protected: /** * Handles a sync request from the emulated application and writes the response to the command buffer. @@ -55,6 +69,10 @@ private: * but once that is implemented we'll need to properly translate all descriptors in the command buffer. */ ResultCode TranslateRequest(Kernel::SharedPtr server_session); + + /// 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> connected_sessions; }; /** From deb83c9fc5c27ca8c50db0b00deb9cd798a814e7 Mon Sep 17 00:00:00 2001 From: Subv Date: Fri, 9 Dec 2016 12:39:12 -0500 Subject: [PATCH 16/18] Kernel/IPC: Small codestyle cleanup --- src/core/hle/ipc.h | 2 -- src/core/hle/service/service.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 90ea4d191..79ccaaed0 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -9,9 +9,7 @@ #include "core/memory.h" namespace Kernel { -class ServerSession; -// TODO(Subv): Move these declarations out of here static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header /** diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 167cb09a8..4f973c634 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -94,8 +94,8 @@ ResultCode SessionRequestHandler::TranslateRequest(Kernel::SharedPtr server_session) { // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which session triggered each command. From ebbb55ec8f827096f1c743cc4b7f4a2aa05a3ed3 Mon Sep 17 00:00:00 2001 From: Subv Date: Fri, 9 Dec 2016 12:52:12 -0500 Subject: [PATCH 17/18] Moved the HLE command buffer translation task to ServerSession instead of the HLE handler superclass. --- src/core/hle/kernel/server_session.cpp | 15 +++++++++++-- src/core/hle/kernel/server_session.h | 10 +++++++++ src/core/hle/service/fs/archive.cpp | 4 ++-- src/core/hle/service/fs/archive.h | 4 ++-- src/core/hle/service/service.cpp | 22 +------------------ src/core/hle/service/service.h | 30 +++++++++----------------- 6 files changed, 38 insertions(+), 47 deletions(-) diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 3fac6b934..1e54c3a2e 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -41,8 +41,14 @@ ResultCode ServerSession::HandleSyncRequest() { // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or similar. // If this ServerSession has an associated HLE handler, forward the request to it. - if (hle_handler != nullptr) - return hle_handler->HandleSyncRequest(SharedPtr(this)); + if (hle_handler != nullptr) { + // Attempt to translate the incoming request's command buffer. + ResultCode result = TranslateHLERequest(this); + if (result.IsError()) + return result; + hle_handler->HandleSyncRequest(SharedPtr(this)); + // TODO(Subv): Translate the response command buffer. + } // If this ServerSession does not have an HLE implementation, just wake up the threads waiting on it. signaled = true; @@ -60,4 +66,9 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& n return std::make_tuple(std::move(server_session), std::move(client_session)); } +ResultCode TranslateHLERequest(ServerSession* server_session) { + // TODO(Subv): Implement this function once multiple concurrent processes are supported. + return RESULT_SUCCESS; +} + } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 7f00db07b..7abc09011 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -76,4 +76,14 @@ private: */ static ResultVal> Create(std::string name = "Unknown", std::shared_ptr hle_handler = nullptr); }; + +/** + * Performs command buffer translation for an HLE IPC request. + * The command buffer from the ServerSession thread's TLS is copied into a + * buffer and all descriptors in the buffer are processed. + * TODO(Subv): Implement this function, currently we do not support multiple processes running at once, + * but once that is implemented we'll need to properly translate all descriptors in the command buffer. + */ +ResultCode TranslateHLERequest(ServerSession* server_session); + } diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index b63c6eaac..bca57061e 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -93,7 +93,7 @@ File::File(std::unique_ptr&& backend, const FileSys::Path& File::~File() {} -void File::HandleSyncRequestImpl(Kernel::SharedPtr server_session) { +void File::HandleSyncRequest(Kernel::SharedPtr server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); FileCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { @@ -207,7 +207,7 @@ Directory::Directory(std::unique_ptr&& backend, Directory::~Directory() {} -void Directory::HandleSyncRequestImpl(Kernel::SharedPtr server_session) { +void Directory::HandleSyncRequest(Kernel::SharedPtr server_session) { u32* cmd_buff = Kernel::GetCommandBuffer(); DirectoryCommand cmd = static_cast(cmd_buff[0]); switch (cmd) { diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 09a922fb5..eb76706a1 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -55,7 +55,7 @@ public: std::unique_ptr backend; ///< File backend interface protected: - void HandleSyncRequestImpl(Kernel::SharedPtr server_session) override; + void HandleSyncRequest(Kernel::SharedPtr server_session) override; }; class Directory final : public SessionRequestHandler { @@ -71,7 +71,7 @@ public: std::unique_ptr backend; ///< File backend interface protected: - void HandleSyncRequestImpl(Kernel::SharedPtr server_session) override; + void HandleSyncRequest(Kernel::SharedPtr server_session) override; }; /** diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 4f973c634..418b128b1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -66,21 +66,6 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -ResultCode SessionRequestHandler::HandleSyncRequest(Kernel::SharedPtr server_session) { - // Attempt to translate the incoming request's command buffer. - ResultCode result = TranslateRequest(server_session); - - if (result.IsError()) - return result; - - // Actually handle the request - HandleSyncRequestImpl(server_session); - - // TODO(Subv): Translate the response command buffer. - - return RESULT_SUCCESS; -} - void SessionRequestHandler::ClientConnected(Kernel::SharedPtr server_session) { connected_sessions.push_back(server_session); } @@ -89,15 +74,10 @@ void SessionRequestHandler::ClientDisconnected(Kernel::SharedPtr server_session) { - // TODO(Subv): Implement this function once multiple concurrent processes are supported. - return RESULT_SUCCESS; -} - Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} Interface::~Interface() = default; -void Interface::HandleSyncRequestImpl(Kernel::SharedPtr server_session) { +void Interface::HandleSyncRequest(Kernel::SharedPtr server_session) { // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which session triggered each command. u32* cmd_buff = Kernel::GetCommandBuffer(); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 2293b473a..a3af48684 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -15,6 +15,11 @@ #include "core/hle/result.h" #include "core/memory.h" + +namespace Kernel { +class ServerSession; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace Service @@ -31,12 +36,14 @@ static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maxim class SessionRequestHandler { public: /** - * Dispatches and handles a sync request from the emulated application. + * Handles a sync request from the emulated application. * @param server_session The ServerSession that was triggered for this sync request, * it should be used to differentiate which client (As in ClientSession) we're answering to. + * TODO(Subv): Use a wrapper structure to hold all the information relevant to + * this request (ServerSession, Originator thread, Translated command buffer, etc). * @returns ResultCode the result code of the translate operation. */ - ResultCode HandleSyncRequest(Kernel::SharedPtr server_session); + virtual void HandleSyncRequest(Kernel::SharedPtr server_session) = 0; /** * Signals that a client has just connected to this HLE handler and keeps the @@ -53,23 +60,6 @@ public: void ClientDisconnected(Kernel::SharedPtr server_session); protected: - /** - * Handles a sync request from the emulated application and writes the response to the command buffer. - * TODO(Subv): Use a wrapper structure to hold all the information relevant to - * this request (ServerSession, Originator thread, Translated command buffer, etc). - */ - virtual void HandleSyncRequestImpl(Kernel::SharedPtr server_session) = 0; - -private: - /** - * Performs command buffer translation for this request. - * The command buffer from the ServerSession thread's TLS is copied into a - * buffer and all descriptors in the buffer are processed. - * TODO(Subv): Implement this function, currently we do not support multiple processes running at once, - * but once that is implemented we'll need to properly translate all descriptors in the command buffer. - */ - ResultCode TranslateRequest(Kernel::SharedPtr server_session); - /// 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> connected_sessions; @@ -120,7 +110,7 @@ public: } protected: - void HandleSyncRequestImpl(Kernel::SharedPtr server_session) override; + void HandleSyncRequest(Kernel::SharedPtr server_session) override; /** * Registers the functions in the service From 016307ae656afc85ab59a5c2598205ef81f99231 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 14 Dec 2016 12:33:49 -0500 Subject: [PATCH 18/18] Fixed the codestyle to match our clang-format rules. --- src/core/hle/ipc.h | 2 +- src/core/hle/kernel/client_port.cpp | 6 ++++-- src/core/hle/kernel/client_port.h | 5 +++-- src/core/hle/kernel/client_session.cpp | 9 ++++++--- src/core/hle/kernel/client_session.h | 11 ++++++----- src/core/hle/kernel/server_port.cpp | 3 ++- src/core/hle/kernel/server_session.cpp | 25 +++++++++++++++---------- src/core/hle/kernel/server_session.h | 25 +++++++++++++++---------- src/core/hle/service/apt/apt.h | 3 ++- src/core/hle/service/fs/archive.cpp | 10 ++++++---- src/core/hle/service/fs/archive.h | 6 +++--- src/core/hle/service/fs/fs_user.cpp | 21 +++++++++++++++------ src/core/hle/service/service.cpp | 21 ++++++++++++--------- src/core/hle/service/service.h | 21 +++++++++++++-------- src/core/hle/service/srv.cpp | 2 +- src/core/hle/svc.cpp | 6 ++++-- 16 files changed, 108 insertions(+), 68 deletions(-) diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 79ccaaed0..4e094faa7 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -139,7 +139,7 @@ union MappedBufferDescInfo { }; inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { - return{ desc }; + return {desc}; } inline DescriptorType GetDescriptorType(u32 descriptor) { diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index bd8ef055d..22645f4ec 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -19,7 +19,8 @@ ResultVal> ClientPort::Connect() { // AcceptSession before returning from this call. if (active_sessions >= max_sessions) { - // TODO(Subv): Return an error code in this situation after session disconnection is implemented. + // TODO(Subv): Return an error code in this situation after session disconnection is + // implemented. /*return ResultCode(ErrorDescription::MaxConnectionsReached, ErrorModule::OS, ErrorSummary::WouldBlock, ErrorLevel::Temporary);*/ @@ -27,7 +28,8 @@ ResultVal> ClientPort::Connect() { active_sessions++; // Create a new session pair, let the created sessions inherit the parent port's HLE handler. - auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); + auto sessions = + ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); auto client_session = std::get>(sessions); auto server_session = std::get>(sessions); diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 0039cf028..511490c7c 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -29,8 +29,9 @@ public: } /** - * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's list of pending sessions, - * and signals the ServerPort, causing any threads waiting on it to awake. + * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's + * list of pending sessions, and signals the ServerPort, causing any threads + * waiting on it to awake. * @returns ClientSession The client endpoint of the created Session pair, or error code. */ ResultVal> Connect(); diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 17302baca..0331386ec 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -11,16 +11,19 @@ namespace Kernel { ClientSession::ClientSession() = default; ClientSession::~ClientSession() { - // This destructor will be called automatically when the last ClientSession handle is closed by the emulated application. + // This destructor will be called automatically when the last ClientSession handle is closed by + // the emulated application. if (server_session->hle_handler) server_session->hle_handler->ClientDisconnected(server_session); // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client), - // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to 0xC920181A. + // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to + // 0xC920181A. } -ResultVal> ClientSession::Create(ServerSession* server_session, std::string name) { +ResultVal> ClientSession::Create(ServerSession* server_session, + std::string name) { SharedPtr client_session(new ClientSession); client_session->name = std::move(name); diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index fedbd0625..ed468dec6 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -4,8 +4,8 @@ #pragma once -#include #include +#include #include "common/common_types.h" @@ -44,9 +44,9 @@ public: */ ResultCode SendSyncRequest(); - std::string name; ///< Name of client port (optional) - ServerSession* server_session; ///< The server session associated with this client session. - SessionStatus session_status; ///< The session's current status. + std::string name; ///< Name of client port (optional) + ServerSession* server_session; ///< The server session associated with this client session. + SessionStatus session_status; ///< The session's current status. private: ClientSession(); @@ -58,7 +58,8 @@ private: * @param name Optional name of client session * @return The created client session */ - static ResultVal> Create(ServerSession* server_session, std::string name = "Unknown"); + static ResultVal> Create(ServerSession* server_session, + std::string name = "Unknown"); }; } // namespace diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index f7699f023..6c19aa7c0 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -24,7 +24,8 @@ void ServerPort::Acquire() { } std::tuple, SharedPtr> ServerPort::CreatePortPair( - u32 max_sessions, std::string name, std::shared_ptr hle_handler) { + u32 max_sessions, std::string name, + std::shared_ptr hle_handler) { SharedPtr server_port(new ServerPort); SharedPtr client_port(new ClientPort); diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 1e54c3a2e..146458c1c 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -12,12 +12,14 @@ namespace Kernel { ServerSession::ServerSession() = default; ServerSession::~ServerSession() { - // This destructor will be called automatically when the last ServerSession handle is closed by the emulated application. + // This destructor will be called automatically when the last ServerSession handle is closed by + // the emulated application. // TODO(Subv): Reduce the ClientPort's connection count, // if the session is still open, set the connection status to 3 (Closed by server), } -ResultVal> ServerSession::Create(std::string name, std::shared_ptr hle_handler) { +ResultVal> ServerSession::Create( + std::string name, std::shared_ptr hle_handler) { SharedPtr server_session(new ServerSession); server_session->name = std::move(name); @@ -38,7 +40,8 @@ void ServerSession::Acquire() { ResultCode ServerSession::HandleSyncRequest() { // The ServerSession received a sync request, this means that there's new data available - // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or similar. + // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or + // similar. // If this ServerSession has an associated HLE handler, forward the request to it. if (hle_handler != nullptr) { @@ -50,17 +53,20 @@ ResultCode ServerSession::HandleSyncRequest() { // TODO(Subv): Translate the response command buffer. } - // If this ServerSession does not have an HLE implementation, just wake up the threads waiting on it. + // If this ServerSession does not have an HLE implementation, just wake up the threads waiting + // on it. signaled = true; WakeupAllWaitingThreads(); return RESULT_SUCCESS; } -ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name, - std::shared_ptr hle_handler) { - auto server_session = ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); - // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want to prevent the - // ServerSession's destructor from being called when the emulated application closes the last ServerSession handle. +ServerSession::SessionPair ServerSession::CreateSessionPair( + const std::string& name, std::shared_ptr hle_handler) { + auto server_session = + ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); + // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want + // to prevent the ServerSession's destructor from being called when the emulated + // application closes the last ServerSession handle. auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom(); return std::make_tuple(std::move(server_session), std::move(client_session)); @@ -70,5 +76,4 @@ ResultCode TranslateHLERequest(ServerSession* server_session) { // TODO(Subv): Implement this function once multiple concurrent processes are supported. return RESULT_SUCCESS; } - } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 7abc09011..458284a5d 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -24,10 +24,10 @@ class ClientSession; * * To make a service call, the client must write the command header and parameters to the buffer * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest - * SVC call with its ClientSession handle. The kernel will read the command header, using it to marshall - * the parameters to the process at the server endpoint of the session. After the server replies to - * the request, the response is marshalled back to the caller's TLS buffer and control is - * transferred back to it. + * SVC call with its ClientSession handle. The kernel will read the command header, using it to + * marshall the parameters to the process at the server endpoint of the session. + * After the server replies to the request, the response is marshalled back to the caller's + * TLS buffer and control is transferred back to it. */ class ServerSession final : public WaitObject { public: @@ -47,7 +47,9 @@ public: * @param name Optional name of the ports * @return The created session tuple */ - static SessionPair CreateSessionPair(const std::string& name = "Unknown", std::shared_ptr hle_handler = nullptr); + static SessionPair CreateSessionPair( + const std::string& name = "Unknown", + std::shared_ptr hle_handler = nullptr); /** * Handle a sync request from the emulated application. @@ -61,7 +63,8 @@ public: std::string name; ///< The name of this session (optional) bool signaled; ///< Whether there's new data available to this ServerSession - std::shared_ptr hle_handler; ///< This session's HLE request handler (optional) + std::shared_ptr + hle_handler; ///< This session's HLE request handler (optional) private: ServerSession(); @@ -74,16 +77,18 @@ private: * @param hle_handler Optional HLE handler for this server session. * @return The created server session */ - static ResultVal> Create(std::string name = "Unknown", std::shared_ptr hle_handler = nullptr); + static ResultVal> Create( + std::string name = "Unknown", + std::shared_ptr hle_handler = nullptr); }; /** * Performs command buffer translation for an HLE IPC request. * The command buffer from the ServerSession thread's TLS is copied into a * buffer and all descriptors in the buffer are processed. - * TODO(Subv): Implement this function, currently we do not support multiple processes running at once, - * but once that is implemented we'll need to properly translate all descriptors in the command buffer. + * TODO(Subv): Implement this function, currently we do not support multiple processes running at + * once, but once that is implemented we'll need to properly translate all descriptors + * in the command buffer. */ ResultCode TranslateHLERequest(ServerSession* server_session); - } diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 9bc6327ed..bcc437f93 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -14,7 +14,8 @@ class Interface; namespace APT { -static const u32 MaxAPTSessions = 2; ///< Each APT service can only have up to 2 sessions connected at the same time. +/// Each APT service can only have up to 2 sessions connected at the same time. +static const u32 MaxAPTSessions = 2; /// Holds information about the parameters used in Send/Glance/ReceiveParameter struct MessageParameter { diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index bca57061e..6184e6f1b 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -175,7 +175,9 @@ void File::HandleSyncRequest(Kernel::SharedPtr server_ses LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); ClientConnected(std::get>(sessions)); - cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).ValueOr(INVALID_HANDLE); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get>(sessions)) + .ValueOr(INVALID_HANDLE); break; } @@ -307,8 +309,8 @@ ResultCode RegisterArchiveType(std::unique_ptr&& factor } ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode) { + const FileSys::Path& path, + const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; @@ -398,7 +400,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, } ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path) { + const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return ERR_INVALID_ARCHIVE_HANDLE; diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index eb76706a1..82d591897 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -104,8 +104,8 @@ ResultCode RegisterArchiveType(std::unique_ptr&& factor * @return The opened File object */ ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode); + const FileSys::Path& path, + const FileSys::Mode mode); /** * Delete a File from an Archive @@ -183,7 +183,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, * @return The opened Directory object */ ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path); + const FileSys::Path& path); /** * Get the free space in an Archive diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index ea1050fb6..0b03bea22 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -68,13 +68,16 @@ static void OpenFile(Service::Interface* self) { LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - ResultVal> file_res = OpenFileFromArchive(archive_handle, file_path, mode); + ResultVal> file_res = + OpenFileFromArchive(archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { std::shared_ptr file = *file_res; auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); file->ClientConnected(std::get>(sessions)); - cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get>(sessions)) + .MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); @@ -131,13 +134,16 @@ static void OpenFileDirectly(Service::Interface* self) { } SCOPE_EXIT({ CloseArchive(*archive_handle); }); - ResultVal> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); + ResultVal> file_res = + OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = file_res.Code().raw; if (file_res.Succeeded()) { std::shared_ptr file = *file_res; auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); file->ClientConnected(std::get>(sessions)); - cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get>(sessions)) + .MoveFrom(); } else { cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", @@ -395,13 +401,16 @@ static void OpenDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast(dirname_type), dirname_size, dir_path.DebugStr().c_str()); - ResultVal> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); + ResultVal> dir_res = + OpenDirectoryFromArchive(archive_handle, dir_path); cmd_buff[1] = dir_res.Code().raw; if (dir_res.Succeeded()) { std::shared_ptr directory = *dir_res; auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); directory->ClientConnected(std::get>(sessions)); - cmd_buff[3] = Kernel::g_handle_table.Create(std::get>(sessions)).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table + .Create(std::get>(sessions)) + .MoveFrom(); } else { LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 418b128b1..9f68898db 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -8,7 +8,6 @@ #include "common/string_util.h" #include "core/hle/kernel/server_port.h" -#include "core/hle/service/service.h" #include "core/hle/service/ac_u.h" #include "core/hle/service/act_a.h" #include "core/hle/service/act_u.h" @@ -66,11 +65,13 @@ static std::string MakeFunctionString(const char* name, const char* port_name, return function_string; } -void SessionRequestHandler::ClientConnected(Kernel::SharedPtr server_session) { +void SessionRequestHandler::ClientConnected( + Kernel::SharedPtr server_session) { connected_sessions.push_back(server_session); } -void SessionRequestHandler::ClientDisconnected(Kernel::SharedPtr server_session) { +void SessionRequestHandler::ClientDisconnected( + Kernel::SharedPtr server_session) { boost::range::remove_erase(connected_sessions, server_session); } @@ -78,7 +79,8 @@ Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} Interface::~Interface() = default; void Interface::HandleSyncRequest(Kernel::SharedPtr server_session) { - // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which session triggered each command. + // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which + // session triggered each command. u32* cmd_buff = Kernel::GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -113,15 +115,17 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), - std::shared_ptr(interface_)); + auto ports = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr(interface_)); auto client_port = std::get>(ports); g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); } void AddService(Interface* interface_) { - auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), - std::shared_ptr(interface_)); + auto ports = + Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), + std::shared_ptr(interface_)); auto client_port = std::get>(ports); g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); } @@ -190,5 +194,4 @@ void Shutdown() { 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 a3af48684..a7ba7688f 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -15,7 +15,6 @@ #include "core/hle/result.h" #include "core/memory.h" - namespace Kernel { class ServerSession; } @@ -26,12 +25,13 @@ class ServerSession; namespace Service { static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) -static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE service +/// Arbitrary default number of maximum connections to an HLE service. +static const u32 DefaultMaxSessions = 10; /** * Interface implemented by HLE Session handlers. - * This can be provided to a ServerSession in order to hook into several relevant events (such as a new connection or a SyncRequest) - * so they can be implemented in the emulator. + * This can be provided to a ServerSession in order to hook into several relevant events + * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. */ class SessionRequestHandler { public: @@ -61,12 +61,14 @@ public: 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. + /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list + // for the duration of the connection. std::vector> connected_sessions; }; /** - * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a table mapping header ids to handler functions. + * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a + * table mapping header ids to handler functions. */ class Interface : public SessionRequestHandler { public: @@ -88,10 +90,13 @@ public: } /** - * Gets the maximum allowed number of sessions that can be connected to this service at the same time. + * Gets the maximum allowed number of sessions that can be connected to this service + * at the same time. * @returns The maximum number of connections allowed. */ - u32 GetMaxSessions() const { return max_sessions; } + u32 GetMaxSessions() const { + return max_sessions; + } typedef void (*Function)(Interface*); diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 37420201b..18d0a699d 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -7,8 +7,8 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/service/srv.h" //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index f24b5c91a..e5ba9a484 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -236,14 +236,16 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Handle handle) { - SharedPtr session = Kernel::g_handle_table.Get(handle); + SharedPtr session = + Kernel::g_handle_table.Get(handle); if (session == nullptr) { return ERR_INVALID_HANDLE; } LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); - // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server responds and cause a reschedule. + // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server + // responds and cause a reschedule. return session->SendSyncRequest(); }